TypeError: method () ใช้เวลา 1 อาร์กิวเมนต์ตำแหน่ง แต่ได้รับ 2


270

ถ้าฉันมีคลาส ...

class MyClass:

    def method(arg):
        print(arg)

... ที่ฉันใช้ในการสร้างวัตถุ ...

my_object = MyClass()

... ที่ฉันเรียกmethod("foo")เช่นนั้น ...

>>> my_object.method("foo")
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: method() takes exactly 1 positional argument (2 given)

... ทำไมหลามถึงบอกว่าฉันให้สองข้อโต้แย้งเมื่อฉันให้เพียงอันเดียว?


ข้อความนั้นมีสาเหตุมากมาย selfเหตุผลที่เฉพาะเจาะจงที่นี่คือว่าวิธีการเช่นทั้งหมดคาดว่าจะหาเรื่องแรกซึ่งโดยการเรียกเรากำหนดเอง ดังนั้นประกาศที่ไม่ถูกต้องสำหรับวิธีการที่มันควรจะเป็นdef method(arg): def method(self, arg):เมื่อวิธีการจัดส่งพยายามที่จะเรียกmethod(arg):และจับคู่สองพารามิเตอร์self, argกับมันคุณจะได้รับข้อผิดพลาดที่
smci

คำตอบ:


367

ใน Python สิ่งนี้:

my_object.method("foo")

... คือน้ำตาลประโยคซึ่งล่ามแปลอยู่เบื้องหลัง:

MyClass.method(my_object, "foo")

... ซึ่งตามที่คุณเห็นจริง ๆ แล้วมีสองข้อโต้แย้ง - มันเป็นเพียงที่แรกคือโดยปริยายจากมุมมองของผู้โทร

นี่เป็นเพราะวิธีการส่วนใหญ่ทำงานกับวัตถุที่พวกเขาเรียกบนดังนั้นจึงจำเป็นต้องมีวิธีที่จะเรียกวัตถุภายในวิธี โดยการประชุมอาร์กิวเมนต์แรกนี้เรียกว่าselfภายในนิยามวิธีการ:

class MyNewClass:

    def method(self, arg):
        print(self)
        print(arg)

หากคุณโทรmethod("foo")หาอินสแตนซ์ของMyNewClassมันจะทำงานได้ตามที่คาดไว้:

>>> my_new_object = MyNewClass()
>>> my_new_object.method("foo")
<__main__.MyNewClass object at 0x29045d0>
foo

บางครั้ง (แต่ไม่บ่อยนัก) คุณไม่สนใจวัตถุที่วิธีการของคุณผูกไว้และในกรณีนั้นคุณสามารถตกแต่งวิธีด้วยstaticmethod()ฟังก์ชันbuiltin เพื่อพูดดังนี้:

class MyOtherClass:

    @staticmethod
    def method(arg):
        print(arg)

... ซึ่งในกรณีนี้คุณไม่จำเป็นต้องเพิ่มselfอาร์กิวเมนต์ในนิยามเมธอดและยังใช้งานได้:

>>> my_other_object = MyOtherClass()
>>> my_other_object.method("foo")
foo

99
ในระยะสั้น: การเพิ่มselfเป็นอาร์กิวเมนต์แรกของวิธีการแก้ปัญหา
amoebe

@amoebe - ประเภทบุคคลของฉัน
Carlos

21

สิ่งอื่นที่ควรพิจารณาเมื่อพบข้อผิดพลาดประเภทนี้:

ฉันพบข้อความแสดงข้อผิดพลาดนี้และพบว่าโพสต์นี้มีประโยชน์ ปรากฎในกรณีของฉันฉันได้แทนที่สิ่ง__init__()ที่มีการสืบทอดวัตถุ

ตัวอย่างที่สืบทอดมานั้นค่อนข้างยาวดังนั้นฉันจะข้ามไปยังตัวอย่างง่ายๆที่ไม่ใช้การสืบทอด:

class MyBadInitClass:
    def ___init__(self, name):
        self.name = name

    def name_foo(self, arg):
        print(self)
        print(arg)
        print("My name is", self.name)


class MyNewClass:
    def new_foo(self, arg):
        print(self)
        print(arg)


my_new_object = MyNewClass()
my_new_object.new_foo("NewFoo")
my_bad_init_object = MyBadInitClass(name="Test Name")
my_bad_init_object.name_foo("name foo")

ผลลัพธ์คือ:

<__main__.MyNewClass object at 0x033C48D0>
NewFoo
Traceback (most recent call last):
  File "C:/Users/Orange/PycharmProjects/Chapter9/bad_init_example.py", line 41, in <module>
    my_bad_init_object = MyBadInitClass(name="Test Name")
TypeError: object() takes no parameters

PyCharm ไม่ได้จับตัวพิมพ์นี้ หรือ Notepad ++ (อาจเป็นบรรณาธิการ / IDE อื่น ๆ )

ได้รับนี่คือ "ไม่ใช้พารามิเตอร์" TypeError มันไม่แตกต่างจาก "มีสอง" มากเมื่อคาดหวังหนึ่งในแง่ของการเริ่มต้นวัตถุใน Python

การกำหนดแอดเดรสของหัวข้อ: initializer การโอเวอร์โหลดจะถูกใช้หากถูกต้องทางไวยากรณ์ แต่ถ้าไม่ใช่จะถูกละเว้นและจะใช้บิวด์อินแทน วัตถุไม่คาดหวัง / จัดการกับสิ่งนี้และเกิดข้อผิดพลาดขึ้น

ในกรณีที่มีข้อผิดพลาดทางไวยากรณ์: การแก้ไขง่าย ๆ เพียงแก้ไขคำสั่ง init ที่กำหนดเอง:

def __init__(self, name):
    self.name = name

1
ไม่มีSyntaxErrorที่นี่ รหัสถูกต้องทางไวยากรณ์ มันก็ถูกต้องกำหนดวิธีการตั้งชื่อซึ่งไม่มีใครเคยไปเรียกร้องแทนวิธีพิเศษ___init__ __init__นั่นเป็นสาเหตุที่ไม่มีการตรวจพบข้อผิดพลาด - เนื่องจากไม่มีการตรวจจับ
abarnert

14

ในคำง่าย ๆ

ใน Python คุณควรเพิ่มselfอาร์กิวเมนต์เป็นอาร์กิวเมนต์แรกของวิธีที่กำหนดไว้ทั้งหมดในคลาส:

class MyClass:
  def method(self, arg):
    print(arg)

จากนั้นคุณสามารถใช้วิธีการตามสัญชาตญาณของคุณ:

>>> my_object = MyClass()
>>> my_object.method("foo")
foo

สิ่งนี้จะช่วยแก้ปัญหาของคุณ :)

เพื่อความเข้าใจที่ดีขึ้นคุณสามารถอ่านคำตอบของคำถามนี้: จุดประสงค์ของตัวเองคืออะไร?


2
เกิดอะไรขึ้นกับคำตอบนี้ ทำไมบางคนถึงให้คะแนนที่เป็นลบกับเธอ? ท้ายที่สุดมันเป็นคำตอบสำหรับคำถามและมีความแตกต่างจากความเรียบง่ายเมื่อเทียบกับคำตอบอื่น ๆ ซึ่งอาจมีความสำคัญสำหรับบางคนที่กำลังมองหาคำตอบ ไม่ใช่เหรอ
simhumileco

10

ใหม่กับ Python ฉันมีปัญหานี้เมื่อฉันใช้**ฟีเจอร์ของ Python ในทางที่ผิด กำลังพยายามโทรหาคำจำกัดความนี้จากที่อื่น:

def create_properties_frame(self, parent, **kwargs):

การใช้สายที่ไม่มีดาวคู่เป็นสาเหตุของปัญหา:

self.create_properties_frame(frame, kw_gsp)

TypeError: create_properties_frame () รับอาร์กิวเมนต์ 2 ตำแหน่ง แต่ได้รับ 3 อาร์กิวเมนต์

ทางออกคือการเพิ่ม**ไปยังข้อโต้แย้ง:

self.create_properties_frame(frame, **kw_gsp)

1
มาจาก JavaScript ฉันคาดหวังว่าจะสามารถส่งรายการหรือพจนานุกรมเป็นอาร์กิวเมนต์ แต่ดูเหมือนว่านั่นไม่ใช่วิธีการทำงานของ Python: คุณต้องปรับโครงสร้างรายการด้วย * หรือ ** ซึ่งเป็นรายการหลังสำหรับรายการอาร์กิวเมนต์ที่มีคีย์เวิร์ด
สมองน้อย

1
@ LittleBrain: ใช่คุณสามารถส่งรายการ (หรือ dict) หากคุณต้องการให้ถือว่าเป็นรายการ (/ dict) ภายในฟังก์ชัน แต่ถ้าคุณต้องการให้แต่ละค่าแตกออกมาและจับคู่กับ args (/ kwargs) ในฟังก์ชั่นคุณต้องใช้*args(/ **kwargs) ไวยากรณ์
smci

9

มันเกิดขึ้นเมื่อคุณไม่ได้ระบุจำนวนพารามิเตอร์__init__()หรือวิธีการอื่นที่กำลังมองหา

ตัวอย่างเช่น:

class Dog:
    def __init__(self):
        print("IN INIT METHOD")

    def __unicode__(self,):
        print("IN UNICODE METHOD")

    def __str__(self):
        print("IN STR METHOD")

obj=Dog("JIMMY",1,2,3,"WOOF")

เมื่อคุณเรียกใช้โปรแกรมด้านบนมันจะทำให้คุณมีข้อผิดพลาดดังนี้:

TypeError: __init __ () รับอาร์กิวเมนต์ 1 ตำแหน่ง แต่ได้รับ 6 อาร์กิวเมนต์

เราจะกำจัดสิ่งนี้ได้อย่างไร

เพียงผ่านพารามิเตอร์__init__()วิธีการที่กำลังมองหา

class Dog:
    def __init__(self, dogname, dob_d, dob_m, dob_y, dogSpeakText):
        self.name_of_dog = dogname
        self.date_of_birth = dob_d
        self.month_of_birth = dob_m
        self.year_of_birth = dob_y
        self.sound_it_make = dogSpeakText

    def __unicode__(self, ):
        print("IN UNICODE METHOD")

    def __str__(self):
        print("IN STR METHOD")


obj = Dog("JIMMY", 1, 2, 3, "WOOF")
print(id(obj))

1

คุณควรสร้างคลาสจริง:

class accum:
    def __init__(self):
        self.acc = 0
    def accumulator(self, var2add, end):
        if not end:
            self.acc+=var2add
    return self.acc


โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.