TypeError: method () leva 1 argumento posicional, mas 2 foram dados


271

Se eu tiver uma aula ...

class MyClass:

    def method(arg):
        print(arg)

... que eu uso para criar um objeto ...

my_object = MyClass()

... no qual eu chamo method("foo")assim ...

>>> 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 que o Python me disse que eu dei dois argumentos, quando eu só dei um?


Essa mensagem tem muitas causas; a razão específica aqui é que todos os métodos de instância esperam um primeiro argumento que, por costume, chamamos self. Portanto, declarar def method(arg):está errado para um método, deveria estar def method(self, arg):. Quando o despacho do método tenta chamar method(arg):e combinar dois parâmetros self, arg, você recebe esse erro.
smci

Respostas:


368

Em Python, isso:

my_object.method("foo")

... é açúcar sintático , que o intérprete traduz nos bastidores em:

MyClass.method(my_object, "foo")

... que, como você pode ver, realmente tem dois argumentos - é apenas o primeiro que está implícito, do ponto de vista do chamador.

Isso ocorre porque a maioria dos métodos trabalha com o objeto em que é chamado, portanto, é necessário que haja alguma maneira de referir esse objeto dentro do método. Por convenção, esse primeiro argumento é chamado selfdentro da definição do método:

class MyNewClass:

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

Se você chamar method("foo")uma instância de MyNewClass, ela funcionará conforme o esperado:

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

Ocasionalmente (mas não com freqüência), você realmente não se importa com o objeto ao qual seu método está vinculado e, nessa circunstância, pode decorar o método com a staticmethod()função interna para dizer isso:

class MyOtherClass:

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

... nesse caso, você não precisa adicionar um selfargumento à definição do método, e ele ainda funciona:

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

99
Em resumo: adicionar selfcomo primeiro argumento ao método resolve o problema.
Amebe

@amoebe - meu tipo de pessoa
Carlos

21

Outra coisa a considerar quando esse tipo de erro é encontrado:

Eu estava encontrando esta mensagem de erro e achei esta postagem útil. Acontece que, no meu caso, eu havia substituído um local __init__()onde havia herança de objeto.

O exemplo herdado é bastante longo, então vou pular para um exemplo mais simples que não usa heranç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")

O resultado é:

<__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ão pegou esse erro de digitação. Nem o Notepad ++ (outros editores / IDEs).

Concedido, este é um TypeError "sem parâmetros", não é muito diferente de "obteve dois" ao esperar um, em termos de inicialização de objeto em Python.

Abordando o tópico: Um inicializador de sobrecarga será usado se sintaticamente correto, mas, caso contrário, será ignorado e o incorporado será usado. O objeto não espera / lida com isso e o erro é gerado.

No caso do erro de sintaxe: A correção é simples, basta editar a instrução init customizada:

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

1
Não há SyntaxErroraqui. O código está sintaticamente correto; apenas define corretamente um método chamado ___init__, que ninguém jamais chamará, em vez do método especial __init__. É por isso que nenhum erro é detectado - porque não há um para detectar.
abarnert

14

Em palavras simples.

No Python, você deve adicionar selfargumento como o primeiro argumento a todos os métodos definidos nas classes:

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

Então você pode usar seu método de acordo com sua intuição:

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

Isso deve resolver seu problema :)

Para uma melhor compreensão, você também pode ler as respostas para esta pergunta: Qual é o propósito de si mesmo?


2
O que há de errado com esta resposta? Por que alguém lhe deu um ponto negativo? Afinal, é a resposta para a pergunta e se distingue por sua simplicidade em comparação com outras respostas, o que pode ser importante para algumas pessoas que procuram uma resposta. Não é?
simhumileco

10

Iniciante no Python, tive esse problema quando estava usando o recurso do Python de **maneira errada. Tentando chamar essa definição de algum lugar:

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

o uso de uma chamada sem estrela dupla estava causando o problema:

self.create_properties_frame(frame, kw_gsp)

TypeError: create_properties_frame () recebe 2 argumentos posicionais, mas 3 foram dados

A solução é adicionar **ao argumento:

self.create_properties_frame(frame, **kw_gsp)

1
Vindo do JavaScript, espero poder passar uma lista ou dicionário como argumento. Mas parece que não é assim que o Python funciona: você precisa desestruturar a lista com * ou **, sendo este último uma lista de argumentos com palavras-chave.
Little Brain

1
@LittleBrain: sim, você pode passar uma lista (ou dict) se quiser que eles sejam tratados como uma lista (/ dict) dentro da função. Mas se você deseja que seus valores individuais sejam descompactados e comparados com args (/ kwargs) na função, será necessário a sintaxe *args(/ **kwargs).
smci

9

Isso ocorre quando você não especifica o número de parâmetros __init__()ou qualquer outro método procurando.

Por exemplo:

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

Quando você executa o programa acima, ocorre um erro assim:

TypeError: __init __ () leva 1 argumento posicional, mas 6 foram dados

Como podemos nos livrar dessa coisa?

Basta passar os parâmetros, que __init__()método procura

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

Você realmente deve criar uma classe:

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

0

No meu caso, esqueci de adicionar o ()

Eu estava chamando o método assim

obj = className.myMethod

Mas deveria ser assim

obj = className.myMethod()

-1

Passe o clsparâmetro para @classmethodpara resolver esse problema.

@classmethod
def test(cls):
    return ''
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.