Il metodo class genera "TypeError: ... ha ottenuto più valori per l'argomento della parola chiave ..."


129

Se definisco un metodo di classe con un argomento di parole chiave in questo modo:

class foo(object):
  def foodo(thing=None, thong='not underwear'):
    print thing if thing else "nothing" 
    print 'a thong is',thong

chiamando il metodo genera un TypeError:

myfoo = foo()
myfoo.foodo(thing="something")

...
TypeError: foodo() got multiple values for keyword argument 'thing'

Cosa sta succedendo?


2
Non otterrai mai una risposta soddisfacente sul perché esplicito selfsia meglio che implicito this.
Nurettin,

Risposte:


164

Il problema è che il primo argomento passato ai metodi di classe in Python è sempre una copia dell'istanza di classe su cui viene chiamato il metodo, in genere etichettata self. Se la classe viene dichiarata così:

class foo(object):
  def foodo(self, thing=None, thong='not underwear'):
    print thing if thing else "nothing" 
    print 'a thong is',thong

si comporta come previsto.

Spiegazione:

Senza selfcome primo parametro, quando myfoo.foodo(thing="something")viene eseguito, il foodometodo viene chiamato con argomenti (myfoo, thing="something"). L'istanza myfooviene quindi assegnata thing(poiché thingè il primo parametro dichiarato), ma anche pitone tentativi di assegnare "something"a thing, quindi l'eccezione.

Per dimostrare, prova a eseguirlo con il codice originale:

myfoo.foodo("something")
print
print myfoo

Uscirai come:

<__main__.foo object at 0x321c290>
a thong is something

<__main__.foo object at 0x321c290>

Puoi vedere che a "cosa" è stato assegnato un riferimento all'istanza "myfoo" della classe "pippo". Questa sezione della documentazione spiega come gli argomenti delle funzioni funzionano un po 'di più.


1
nota: è possibile ottenere lo stesso tipo di errore se la funzione def include self come primo parametro e quindi si chiama accidentalmente la funzione anche con self come primo parametro.
Christopher Hunter,

48

Grazie per i post istruttivi. Vorrei solo tenere presente che se si ottiene "TypeError: foodo () ha più valori per l'argomento della parola chiave 'cosa'", potrebbe anche essere che si passi erroneamente il 'sé' come parametro quando chiamando la funzione (probabilmente perché hai copiato la linea dalla dichiarazione di classe - è un errore comune quando si ha fretta).


7
Questo è quello che mi è successo, grazie per aver aggiunto a questa risposta. Questo potrebbe essere l'errore più comune da fare, motivo per cui stai ricevendo il mio voto.
rdrey,

Lo stesso si verifica quando si sovraccarica un @classmethod, la soluzione deve essere utilizzata super().function(...)invece di <parentclass>.function(cls, ...).
Ederag,

30

Questo potrebbe essere ovvio, ma potrebbe aiutare qualcuno che non l'ha mai visto prima. Ciò accade anche per le funzioni regolari se si assegna erroneamente un parametro per posizione ed esplicitamente per nome.

>>> def foodo(thing=None, thong='not underwear'):
...     print thing if thing else "nothing"
...     print 'a thong is',thong
...
>>> foodo('something', thing='everything')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: foodo() got multiple values for keyword argument 'thing'

6

basta aggiungere il decoratore 'staticmethod' alla funzione e il problema è stato risolto

class foo(object):
    @staticmethod
    def foodo(thing=None, thong='not underwear'):
        print thing if thing else "nothing" 
        print 'a thong is',thong

Ho appena ricevuto questo errore e questa soluzione ha risolto il mio problema. Ma puoi approfondire come o perché questo decoratore ha risolto il problema?
Ray,

1
staticmethod interrompe il metodo che riceve self come primo argomento. Quindi ora, se chiami myfoo.foodo(thing="something"), cosa = "qualcosa" verrà assegnato al primo argomento, piuttosto che all'argomento implicito di sé.
danio,

significa anche che non è possibile accedere alle variabili di classe all'interno della funzione, a cui si accede normalmente tramiteself
drevicko,

4

Voglio aggiungere un'altra risposta:

Succede quando si tenta di passare un parametro posizionale con un ordine di posizione errato insieme all'argomento della parola chiave nella funzione di chiamata.

there is difference between parameter and argumentpuoi leggere in dettaglio qui Argomenti e Parametri in Python

def hello(a,b=1, *args):
   print(a, b, *args)


hello(1, 2, 3, 4,a=12)

poiché abbiamo tre parametri:

a è un parametro posizionale

b = 1 è la parola chiave e il parametro predefinito

* args è un parametro di lunghezza variabile

quindi prima assegniamo un parametro posizionale, significa che dobbiamo fornire valore all'argomento posizionale nel suo ordine di posizione, qui l'ordine conta. ma stiamo passando l'argomento 1 al posto di una funzione di chiamata e quindi stiamo fornendo anche valore a, trattando come argomento di parola chiave. ora a hanno due valori:

uno è il valore posizionale: a = 1

il secondo è un valore con parole chiave che è a = 12

Soluzione

Dobbiamo passare hello(1, 2, 3, 4,a=12)a hello(1, 2, 3, 4,12) così ora a otterrà solo un valore posizionale che è 1 e b otterrà valore 2 e il resto dei valori otterrà * args (parametro di lunghezza variabile)

Informazioni aggiuntive

se vogliamo che * args dovrebbe ottenere 2,3,4 e a dovrebbe ottenere 1 e b dovrebbe ottenere 12

allora possiamo fare così
def hello(a,*args,b=1): pass hello(1, 2, 3, 4,b=12)

Qualcosa in più :

def hello(a,*c,b=1,**kwargs):
    print(b)
    print(c)
    print(a)
    print(kwargs)

hello(1,2,1,2,8,9,c=12)

produzione :

1

(2, 1, 2, 8, 9)

1

{'c': 12}

che è già coperto dalla risposta stackoverflow.com/a/31822875/12663 - il tuo esempio ha lo stesso parametro (a) assegnato per posizione e anche esplicitamente per nome.
danio,

3

Questo errore può verificarsi anche se si passa un argomento della parola chiave per il quale una delle chiavi è simile (ha lo stesso nome di stringa) a un argomento posizionale.

>>> class Foo():
...     def bar(self, bar, **kwargs):
...             print(bar)
... 
>>> kwgs = {"bar":"Barred", "jokes":"Another key word argument"}
>>> myfoo = Foo()
>>> myfoo.bar("fire", **kwgs)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: bar() got multiple values for argument 'bar'
>>> 

"fuoco" è stato accettato nell'argomento "bar". Eppure c'è un altro argomento 'bar' presente in kwargs.

Dovresti rimuovere l'argomento della parola chiave da kwargs prima di passarlo al metodo.


1

Anche questo può accadere in Django se stai usando jquery ajax per url che si inverte a una funzione che non contiene il parametro 'request'

$.ajax({
  url: '{{ url_to_myfunc }}',
});


def myfunc(foo, bar):
    ...
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.