TypeError: method () prend 1 argument positionnel mais 2 ont été donnés

271

Si j'ai une classe ...

class MyClass:

    def method(arg):
        print(arg)

... que j'utilise pour créer un objet ...

my_object = MyClass()

... sur laquelle j'appelle method("foo")comme ça ...

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

... pourquoi Python me dit que je lui ai donné deux arguments, alors que je n'en ai donné qu'un?

Zero Piraeus
la source
Ce message a une multitude de causes; la raison spécifique ici est que toutes les méthodes d'instance attendent un premier argument que nous appelons par coutume self. Donc, déclarer def method(arg):est faux pour une méthode, ça devrait l'être def method(self, arg):. Lorsque la méthode dispatch essaie d'appeler method(arg):et de faire correspondre deux paramètres self, argavec elle, vous obtenez cette erreur.
smci

Réponses:

368

En Python, ceci:

my_object.method("foo")

... est du sucre syntaxique , que l'interprète traduit dans les coulisses en:

MyClass.method(my_object, "foo")

... qui, comme vous pouvez le voir, a en effet deux arguments - c'est juste que le premier est implicite, du point de vue de l'appelant.

En effet, la plupart des méthodes fonctionnent avec l'objet auquel elles sont appelées, il doit donc y avoir un moyen de faire référence à cet objet à l'intérieur de la méthode. Par convention, ce premier argument est appelé selfdans la définition de la méthode:

class MyNewClass:

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

Si vous appelez method("foo")une instance de MyNewClass, cela fonctionne comme prévu:

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

Parfois (mais pas souvent), vous ne vous souciez pas vraiment de l'objet auquel votre méthode est liée, et dans ce cas, vous pouvez décorer la méthode avec la staticmethod()fonction intégrée pour le dire:

class MyOtherClass:

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

... dans ce cas, vous n'avez pas besoin d'ajouter un selfargument à la définition de la méthode, et cela fonctionne toujours:

>>> my_other_object = MyOtherClass()
>>> my_other_object.method("foo")
foo
Zero Piraeus
la source
99
En bref: l'ajout selfcomme premier argument à la méthode résout le problème.
amoebe
@amoebe - mon type de personne
Carlos
21

Autre chose à considérer lorsque ce type d'erreur se produit:

Je rencontrais ce message d'erreur et j'ai trouvé ce message utile. Il s'avère que dans mon cas, j'avais remplacé un __init__()héritage d'objets.

L'exemple hérité est assez long, je vais donc passer à un exemple plus simple qui n'utilise pas l'héritage:

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

Le résultat est:

<__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 n'a pas saisi cette faute de frappe. Notepad ++ non plus (d'autres éditeurs / IDE pourraient le faire).

Certes, il s'agit d'un typeError "ne prend aucun paramètre", ce n'est pas très différent de "got two" quand on en attend un, en termes d'initialisation d'objet en Python.

Aborder le sujet: un initialiseur de surcharge sera utilisé s'il est syntaxiquement correct, mais sinon il sera ignoré et le intégré sera utilisé à la place. L'objet ne s'attend pas / ne gère pas cela et l'erreur est levée.

Dans le cas de l'erreur sytax: Le correctif est simple, il suffit de modifier l'instruction init personnalisée:

def __init__(self, name):
    self.name = name
Jonru2016
la source
1
Il n'y en a pas SyntaxErrorici. Le code est syntaxiquement correct; il définit juste correctement une méthode nommée ___init__, que personne ne va jamais appeler, au lieu de la méthode spéciale __init__. C'est pourquoi aucune erreur n'est détectée, car il n'y en a pas à détecter.
abarnert
14

En termes simples.

En Python, vous devez ajouter l' selfargument comme premier argument à toutes les méthodes définies dans les classes:

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

Ensuite, vous pouvez utiliser votre méthode selon votre intuition:

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

Cela devrait résoudre votre problème :)

Pour une meilleure compréhension, vous pouvez également lire les réponses à cette question: quel est le but de soi?

simhumileco
la source
2
Quel est le problème avec cette réponse? Pourquoi quelqu'un lui a-t-il donné un point négatif? Après tout, c'est la réponse à la question et se distingue par sa simplicité par rapport aux autres réponses, ce qui peut être important pour certaines personnes qui recherchent une réponse. N'est-ce pas?
simhumileco
10

Nouveau venu sur Python, j'ai eu ce problème lorsque j'utilisais la fonctionnalité de Python de **manière incorrecte. Essayer d'appeler cette définition quelque part:

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

l'utilisation d'un appel sans double étoile était à l'origine du problème:

self.create_properties_frame(frame, kw_gsp)

TypeError: create_properties_frame () prend 2 arguments positionnels mais 3 ont été donnés

La solution est d'ajouter **à l'argument:

self.create_properties_frame(frame, **kw_gsp)
Stanislav Pankevich
la source
1
Venant de JavaScript, je m'attends à pouvoir passer une liste ou un dictionnaire en argument. Mais il semble que ce ne soit pas ainsi que fonctionne Python: vous devez détruire la liste avec * ou **, ce dernier étant pour une liste d'arguments mot-clé.
Little Brain
1
@LittleBrain: oui, vous pouvez passer une liste (ou dict) si vous voulez qu'ils soient traités comme une liste (/ dict) à l'intérieur de la fonction. Mais si vous voulez que leurs valeurs individuelles soient décompressées et comparées aux arguments (/ kwargs) dans la fonction, alors vous avez besoin de la syntaxe *args(/ **kwargs).
smci
9

Cela se produit lorsque vous ne spécifiez pas le nombre de paramètres que la __init__()ou toute autre méthode recherche.

Par exemple:

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

Lorsque vous exécutez le programme ci-dessus, il vous donne une erreur comme celle-ci:

TypeError: __init __ () prend 1 argument positionnel mais 6 ont été donnés

Comment pouvons-nous nous débarrasser de cette chose?

Passez simplement les paramètres, quelle __init__()méthode recherchez

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
la source
1

Vous devez réellement créer une classe:

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

Dans mon cas, j'ai oublié d'ajouter le ()

J'appelais la méthode comme ça

obj = className.myMethod

Mais ça devrait être comme ça

obj = className.myMethod()
Le juge Bringer
la source
-1

Passez le clsparamètre dans @classmethodpour résoudre ce problème.

@classmethod
def test(cls):
    return ''
Ruan Nawe
la source