TypeError: method () nhận 1 đối số vị trí nhưng 2 được đưa ra


271

Nếu tôi có một lớp ...

class MyClass:

    def method(arg):
        print(arg)

... mà tôi sử dụng để tạo một đối tượng ...

my_object = MyClass()

... Tôi gọi method("foo")như vậy ...

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

... tại sao Python nói với tôi rằng tôi đã đưa ra hai đối số, khi tôi chỉ đưa ra một đối số?


Thông điệp đó có nhiều nguyên nhân; lý do cụ thể ở đây là tất cả các phương thức thể hiện mong đợi một đối số đầu tiên mà theo tùy chỉnh mà chúng ta gọi self. Vì vậy, khai báo def method(arg):là sai cho một phương thức, nó nên được def method(self, arg):. Khi công văn phương thức cố gắng gọi method(arg):và khớp hai tham số self, argvới nó, bạn sẽ gặp lỗi đó.
smci

Câu trả lời:


368

Trong Python, đây:

my_object.method("foo")

... là đường cú pháp , mà trình thông dịch dịch đằng sau hậu trường thành:

MyClass.method(my_object, "foo")

... mà, như bạn có thể thấy, thực sự có hai đối số - chỉ là đối số đầu tiên là ẩn, theo quan điểm của người gọi.

Điều này là do hầu hết các phương thức thực hiện một số công việc với đối tượng mà chúng được gọi, do đó cần có một số cách để đối tượng đó được tham chiếu bên trong phương thức. Theo quy ước, đối số đầu tiên này được gọi selfbên trong định nghĩa phương thức:

class MyNewClass:

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

Nếu bạn gọi method("foo")theo một ví dụ MyNewClass, nó hoạt động như mong đợi:

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

Thỉnh thoảng (nhưng không thường xuyên), bạn thực sự không quan tâm đến đối tượng mà phương thức của bạn bị ràng buộc và trong trường hợp đó, bạn có thể trang trí phương thức với staticmethod()hàm dựng sẵn để nói như vậy:

class MyOtherClass:

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

... trong trường hợp đó bạn không cần thêm selfđối số vào định nghĩa phương thức và nó vẫn hoạt động:

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

99
Tóm lại: Thêm selflàm đối số đầu tiên cho phương thức giải quyết vấn đề.
amoebe

@amoebe - mẫu người của tôi
Carlos

21

Một cái gì đó khác để xem xét khi gặp loại lỗi này:

Tôi đã chạy vào thông báo lỗi này và thấy bài viết này hữu ích. Hóa ra trong trường hợp của tôi, tôi đã ghi đè lên một __init__()nơi có sự kế thừa đối tượng.

Ví dụ được kế thừa khá dài, vì vậy tôi sẽ bỏ qua một ví dụ đơn giản hơn không sử dụng tính kế thừa:

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")

Kết quả là:

<__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 đã không bắt lỗi đánh máy này. Notepad ++ cũng vậy (các trình soạn thảo / IDE khác có thể).

Cấp, đây là TypeError "không có tham số", nó không khác nhiều so với "có hai" khi mong đợi một, về mặt khởi tạo đối tượng trong Python.

Giải quyết chủ đề: Một trình khởi tạo quá tải sẽ được sử dụng nếu đúng về mặt cú pháp, nhưng nếu không, nó sẽ bị bỏ qua và sử dụng tích hợp thay thế. Đối tượng sẽ không mong đợi / xử lý việc này và lỗi được đưa ra.

Trong trường hợp lỗi sytax: Cách khắc phục rất đơn giản, chỉ cần chỉnh sửa câu lệnh init tùy chỉnh:

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

1
Không có SyntaxErrorở đây. Mã này đúng về mặt cú pháp; nó chỉ định nghĩa chính xác một phương thức có tên ___init__, mà không ai sẽ gọi, thay vì phương thức đặc biệt __init__. Đó là lý do tại sao không có lỗi nào được phát hiện bởi vì không có lỗi nào để phát hiện.
abarnert

14

Nói một cách đơn giản.

Trong Python, bạn nên thêm selfđối số làm đối số đầu tiên cho tất cả các phương thức được xác định trong các lớp:

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

Sau đó, bạn có thể sử dụng phương pháp của bạn theo trực giác của bạn:

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

Điều này sẽ giải quyết vấn đề của bạn :)

Để hiểu rõ hơn, bạn cũng có thể đọc câu trả lời cho câu hỏi này: mục đích của bản thân là gì?


2
Có gì sai với câu trả lời này? Tại sao ai đó cho cô ấy một điểm tiêu cực? Rốt cuộc, nó là câu trả lời cho câu hỏi và được phân biệt bởi sự đơn giản của nó so với các câu trả lời khác, điều này có thể quan trọng đối với một số người đang tìm kiếm một câu trả lời. Phải không?
simhumileco

10

Người mới sử dụng Python, tôi gặp vấn đề này khi sử dụng **tính năng của Python một cách sai lầm. Cố gắng gọi định nghĩa này từ đâu đó:

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

sử dụng cuộc gọi mà không có sao đôi đã gây ra sự cố:

self.create_properties_frame(frame, kw_gsp)

TypeError: create_properIES_frame () nhận 2 đối số vị trí nhưng 3 đã được đưa ra

Giải pháp là thêm **vào đối số:

self.create_properties_frame(frame, **kw_gsp)

1
Đến từ JavaScript, tôi hy vọng có thể vượt qua một danh sách hoặc từ điển làm đối số. Nhưng có vẻ như đó không phải là cách Python hoạt động: bạn phải cấu trúc danh sách bằng * hoặc **, sau này là danh sách đối số được từ khóa.
Não nhỏ

1
@LittleBrain: có, bạn có thể vượt qua một danh sách (hoặc dict) nếu bạn muốn chúng được coi là một danh sách (/ dict) bên trong hàm. Nhưng nếu bạn muốn các giá trị riêng lẻ của chúng được giải nén và khớp với các đối số (/ kwargs) trong hàm, thì bạn cần cú pháp *args(/ **kwargs).
smci

9

Nó xảy ra khi bạn không chỉ định không có tham số __init__()nào hoặc bất kỳ phương thức nào khác đang tìm kiếm.

Ví dụ:

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")

Khi bạn chạy chương trình trên, nó sẽ báo lỗi như vậy:

LoạiError: __init __ () nhận 1 đối số vị trí nhưng 6 đã được đưa ra

Làm thế nào chúng ta có thể thoát khỏi điều này?

Chỉ cần truyền tham số, __init__()phương pháp tìm kiếm

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

Bạn thực sự nên tạo một lớp:

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

0

Trong trường hợp của tôi, tôi quên thêm ()

Tôi đã gọi phương thức như thế này

obj = className.myMethod

Nhưng nó nên như thế này

obj = className.myMethod()

-1

Truyền clstham số vào @classmethodđể giải quyết vấn đề này.

@classmethod
def test(cls):
    return ''
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.