TypeError: method () toma 1 argumento posicional pero se dieron 2

271

Si tengo una clase ...

class MyClass:

    def method(arg):
        print(arg)

... que uso para crear un objeto ...

my_object = MyClass()

... en el que llamo method("foo")así ...

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

... ¿por qué Python me dice que le di dos argumentos, cuando solo di uno?

Cero Pireo
fuente
Ese mensaje tiene innumerables causas; La razón específica aquí es que todos los métodos de instancia esperan un primer argumento que por costumbre llamamos self. Entonces declarar def method(arg):es incorrecto para un método, debería serlo def method(self, arg):. Cuando el envío del método intenta llamar method(arg):y hacer coincidir dos parámetros self, argcon él, obtienes ese error.
smci

Respuestas:

368

En Python, esto:

my_object.method("foo")

... es azúcar sintáctica , que el intérprete traduce detrás de escena en:

MyClass.method(my_object, "foo")

... que, como puede ver, tiene dos argumentos: es que el primero es implícito, desde el punto de vista de la persona que llama.

Esto se debe a que la mayoría de los métodos funcionan con el objeto al que están llamados, por lo que debe haber alguna forma de que se haga referencia a ese objeto dentro del método. Por convención, este primer argumento se llama selfdentro de la definición del método:

class MyNewClass:

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

Si llama method("foo")a una instancia de MyNewClass, funciona como se esperaba:

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

Ocasionalmente (pero no con frecuencia), realmente no le importa el objeto al que está vinculado su método, y en esa circunstancia, puede decorar el método con la staticmethod()función incorporada para decirlo:

class MyOtherClass:

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

... en cuyo caso no necesita agregar un selfargumento a la definición del método, y aún funciona:

>>> my_other_object = MyOtherClass()
>>> my_other_object.method("foo")
foo
Cero Pireo
fuente
99
En resumen: agregar selfcomo primer argumento al método resuelve el problema.
amoebe
@amoebe - mi tipo de persona
Carlos
21

Algo más a considerar cuando se encuentra este tipo de error:

Me encontré con este mensaje de error y encontré útil esta publicación. Resulta que en mi caso había anulado un lugar __init__()donde había herencia de objetos.

El ejemplo heredado es bastante largo, por lo que pasaré a un ejemplo más simple que no usa herencia:

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

El resultado es:

<__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 no captó este error tipográfico. Tampoco Notepad ++ (otros editores / IDE podrían).

Por supuesto, este es un TypeError "no toma parámetros", no es muy diferente de "tiene dos" cuando se espera uno, en términos de inicialización de objetos en Python.

Abordar el tema: se usará un inicializador de sobrecarga si es sintácticamente correcto, pero si no se ignorará y se utilizará el incorporado. El objeto no esperará / manejará esto y se arrojará el error.

En el caso del error de sintaxis: la solución es simple, solo edite la instrucción init personalizada:

def __init__(self, name):
    self.name = name
Jonru2016
fuente
1
No hay SyntaxErroraqui. El código es sintácticamente correcto; simplemente define correctamente un método llamado ___init__, que nadie va a llamar, en lugar del método especial __init__. Es por eso que no se detecta ningún error, porque no hay uno para detectar.
abarnert
14

En palabras simples

En Python, debe agregar el selfargumento como primer argumento para todos los métodos definidos en las clases:

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

Luego puede usar su método de acuerdo con su intuición:

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

Esto debería solucionar tu problema :)

Para una mejor comprensión, también puede leer las respuestas a esta pregunta: ¿Cuál es el propósito de uno mismo?

simhumileco
fuente
2
¿Qué hay de malo con esta respuesta? ¿Por qué alguien le dio un punto negativo? Después de todo, es la respuesta a la pregunta y se distingue por su simplicidad en comparación con otras respuestas, lo que puede ser importante para algunas personas que buscan una respuesta. ¿No es así?
simhumileco
10

Recién llegado a Python, tuve este problema cuando estaba usando la **función de Python de forma incorrecta. Intentando llamar a esta definición desde algún lugar:

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

usar una llamada sin una estrella doble estaba causando el problema:

self.create_properties_frame(frame, kw_gsp)

TypeError: create_properties_frame () toma 2 argumentos posicionales pero se dieron 3

La solución es agregar **al argumento:

self.create_properties_frame(frame, **kw_gsp)
Stanislav Pankevich
fuente
1
Viniendo de JavaScript, espero poder pasar una lista o diccionario como argumento. Pero parece que no es así como funciona Python: debe desestructurar la lista con * o **, este último para una lista de argumentos con palabras clave.
Little Brain el
1
@LittleBrain: sí, puede pasar una lista (o dict) si desea que se traten como una lista (/ dict) dentro de la función. Pero si desea desempaquetar sus valores individuales y compararlos con args (/ kwargs) en la función, entonces necesita la sintaxis *args(/ **kwargs).
smci
9

Ocurre cuando no especifica el no de parámetros que el __init__()o cualquier otro método que busca.

Por ejemplo:

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

Cuando ejecuta el programa anterior, le da un error como ese:

TypeError: __init __ () toma 1 argumento posicional pero se dieron 6

¿Cómo podemos deshacernos de esta cosa?

Simplemente pase los parámetros, qué __init__()método está buscando

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
fuente
1

Deberías crear una clase:

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

En mi caso, olvidé agregar el ()

Estaba llamando al método así

obj = className.myMethod

Pero debería ser así

obj = className.myMethod()
Justice Bringer
fuente
-1

Pase el clsparámetro a @classmethodpara resolver este problema.

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