TypeError: method () przyjmuje 1 argument pozycyjny, ale podano 2

270

Jeśli mam klasę ...

class MyClass:

    def method(arg):
        print(arg)

... którego używam do stworzenia obiektu ...

my_object = MyClass()

... na które tak nazywam 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)

... dlaczego Python mówi mi, że podałem mu dwa argumenty, skoro podałem tylko jeden?

Zero Pireus
źródło
Ta wiadomość ma wiele przyczyn; konkretnym powodem jest to, że wszystkie metody instancji oczekują pierwszego argumentu, który niestandardowo wywołujemy self. Dlatego deklarowanie def method(arg):jest niewłaściwe dla metody, powinno być def method(self, arg):. Gdy metoda wysyłki próbuje wywołać method(arg):i dopasować do niego dwa parametry self, arg, pojawia się ten błąd.
smci

Odpowiedzi:

367

W Pythonie to:

my_object.method("foo")

... to cukier składniowy , który tłumacz tłumaczy za kulisami na:

MyClass.method(my_object, "foo")

... które, jak widać, rzeczywiście mają dwa argumenty - po prostu pierwszy jest niejawny z punktu widzenia osoby dzwoniącej.

Wynika to z faktu, że większość metod działa w pewien sposób z obiektem, do którego zostały wywołane, dlatego musi istnieć sposób, aby do obiektu można było się odwoływać w ramach metody. Zgodnie z konwencją pierwszy argument jest wywoływany selfw definicji metody:

class MyNewClass:

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

Wywołanie method("foo")instancji MyNewClassdziała zgodnie z oczekiwaniami:

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

Czasami (ale nie często) tak naprawdę nie obchodzi cię obiekt, do którego twoja metoda jest zobowiązana, iw takiej sytuacji możesz udekorować metodę za pomocą wbudowanej staticmethod()funkcji, aby powiedzieć:

class MyOtherClass:

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

... w takim przypadku nie trzeba dodawać selfargumentu do definicji metody i nadal działa:

>>> my_other_object = MyOtherClass()
>>> my_other_object.method("foo")
foo
Zero Pireus
źródło
99
Krótko mówiąc: dodanie selfpierwszego argumentu do metody rozwiązuje problem.
ameba
@amoebe - mój typ osoby
Carlos
21

Coś innego, co należy wziąć pod uwagę przy napotkaniu tego rodzaju błędu:

Napotkałem ten komunikat o błędzie i uznałem ten post za pomocny. Okazuje się, że w moim przypadku zastąpiłem __init__()dziedziczenie obiektów.

Dziedziczony przykład jest raczej długi, więc przejdę do prostszego przykładu, który nie korzysta z dziedziczenia:

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

Wynik to:

<__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 nie złapał tej literówki. Notepad ++ też (inne edytory / IDE mogą).

To prawda, TypeError „nie przyjmuje parametrów”, nie różni się niczym od „dostania dwóch”, gdy oczekuje się jednego, pod względem inicjalizacji obiektu w Pythonie.

Zajmując się tym tematem: Inicjator przeciążenia zostanie użyty, jeśli jest poprawny pod względem składniowym, ale jeśli nie, zostanie zignorowany i zamiast tego zostanie użyty wbudowany. Obiekt nie oczekuje / nie obsłuży tego, a błąd zostanie zgłoszony.

W przypadku błędu sytax: Poprawka jest prosta, wystarczy edytować niestandardową instrukcję init:

def __init__(self, name):
    self.name = name
Jonru2016
źródło
1
Tu nie ma SyntaxError. Kod jest poprawny pod względem składniowym; po prostu poprawnie definiuje nazwaną metodę ___init__, której nikt nigdy nie wywoła, zamiast metody specjalnej __init__. Dlatego nie wykryto żadnego błędu - ponieważ nie ma jednego do wykrycia.
abarnert
14

W prostych słowach.

W Pythonie powinieneś dodać selfargument jako pierwszy argument do wszystkich zdefiniowanych metod w klasach:

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

Następnie możesz użyć metody zgodnie ze swoją intuicją:

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

To powinno rozwiązać twój problem :)

Aby lepiej zrozumieć, możesz także przeczytać odpowiedzi na to pytanie: Jaki jest cel siebie?

simhumileco
źródło
2
Co jest nie tak z tą odpowiedzią? Dlaczego ktoś dał jej punkt ujemny? W końcu jest to odpowiedź na pytanie i wyróżnia się prostotą w porównaniu z innymi odpowiedziami, co może być ważne dla niektórych osób, które szukają odpowiedzi. Czyż nie
simhumileco
10

Nowicjusz w Pythonie, miałem ten problem, gdy **niewłaściwie korzystałem z funkcji Pythona . Próbuję wywołać gdzieś tę definicję:

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

używanie połączenia bez podwójnej gwiazdki powodowało problem:

self.create_properties_frame(frame, kw_gsp)

TypeError: create_properties_frame () przyjmuje 2 argumenty pozycyjne, ale podano 3

Rozwiązaniem jest dodanie **do argumentu:

self.create_properties_frame(frame, **kw_gsp)
Stanisław Pankiewicz
źródło
1
Pochodząc z JavaScript, spodziewam się, że będę w stanie przekazać listę lub słownik jako argument. Ale wygląda na to, że nie tak działa Python: musisz zniszczyć listę za pomocą * lub **, przy czym ta ostatnia dotyczy listy słów kluczowych.
Little Brain
1
@LittleBrain: tak, możesz przekazać listę (lub dict), jeśli chcesz, aby były traktowane jako lista (/ dict) wewnątrz funkcji. Ale jeśli chcesz, aby ich indywidualne wartości zostały rozpakowane i dopasowane do argumentów (/ kwargs) w funkcji, potrzebujesz składni *args(/ **kwargs).
smci
9

Występuje, gdy nie określisz liczby parametrów __init__()ani żadnej innej szukanej metody.

Na przykład:

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

Po uruchomieniu powyższego programu pojawia się taki błąd:

TypeError: __init __ () przyjmuje 1 argument pozycyjny, ale podano 6

Jak możemy się tego pozbyć?

Wystarczy przekazać parametry, jakiej __init__()metody szukasz

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))
Trinadh Koya
źródło
1

Powinieneś stworzyć klasę:

class accum:
    def __init__(self):
        self.acc = 0
    def accumulator(self, var2add, end):
        if not end:
            self.acc+=var2add
    return self.acc
Coddy
źródło
0

W moim przypadku zapomniałem dodać ()

Nazywałem tę metodę w ten sposób

obj = className.myMethod

Ale tak powinno być

obj = className.myMethod()
Sprawiedliwości Bringer
źródło
-1

Przekaż clsparametr do, @classmethodaby rozwiązać ten problem.

@classmethod
def test(cls):
    return ''
Ruan Nawe
źródło