Jeśli zdefiniuję metodę klasy za pomocą argumentu słowa kluczowego:
class foo(object):
def foodo(thing=None, thong='not underwear'):
print thing if thing else "nothing"
print 'a thong is',thong
wywołanie metody generuje TypeError
:
myfoo = foo()
myfoo.foodo(thing="something")
...
TypeError: foodo() got multiple values for keyword argument 'thing'
Co się dzieje?
python
class
python-2.7
methods
drevicko
źródło
źródło
self
jest lepsze niż niejawnethis
.Odpowiedzi:
Problem polega na tym, że pierwszy argument przekazywany do metod klasowych w Pythonie jest zawsze kopią instancji klasy, na której metoda jest wywoływana, zwykle oznaczoną etykietą
self
. Jeśli klasa jest zadeklarowana w ten sposób:class foo(object): def foodo(self, thing=None, thong='not underwear'): print thing if thing else "nothing" print 'a thong is',thong
zachowuje się zgodnie z oczekiwaniami.
Wyjaśnienie:
Bez
self
pierwszego parametru, gdymyfoo.foodo(thing="something")
jest wykonywana,foodo
metoda jest wywoływana z argumentami(myfoo, thing="something")
. Instancjamyfoo
jest następnie przypisywana dothing
(ponieważthing
jest to pierwszy zadeklarowany parametr), ale Python również próbuje przypisać"something"
dothing
, stąd wyjątek.Aby zademonstrować, spróbuj uruchomić to z oryginalnym kodem:
myfoo.foodo("something") print print myfoo
Będziesz drukować jak:
<__main__.foo object at 0x321c290> a thong is something <__main__.foo object at 0x321c290>
Możesz zobaczyć, że „rzecz” została przypisana jako odniesienie do instancji „myfoo” klasy „foo”. Ta sekcja dokumentacji wyjaśnia nieco bardziej, jak argumenty funkcji działają.
źródło
Dzięki za pouczające posty. Chciałbym tylko zwrócić uwagę, że jeśli otrzymujesz komunikat „TypeError: foodo () ma wiele wartości argumentu słowa kluczowego„ rzecz ””, może być również tak, że omyłkowo przekazujesz „self” jako parametr, gdy wywołanie funkcji (prawdopodobnie dlatego, że skopiowałeś wiersz z deklaracji klasy - to częsty błąd, gdy się spieszysz).
źródło
@classmethod
, rozwiązaniem jest użyciesuper().function(...)
zamiast<parentclass>.function(cls, ...)
.To może być oczywiste, ale może pomóc komuś, kto nigdy wcześniej tego nie widział. Dzieje się tak również w przypadku zwykłych funkcji, jeśli omyłkowo przypiszesz parametr według pozycji i jawnie według nazwy.
>>> 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'
źródło
wystarczy dodać dekorator „staticmethod” do funkcji i problem zostanie naprawiony
class foo(object): @staticmethod def foodo(thing=None, thong='not underwear'): print thing if thing else "nothing" print 'a thong is',thong
źródło
myfoo.foodo(thing="something")
, rzecz = "coś" zostanie przypisana do pierwszego argumentu, a nie do niejawnego argumentu własnego.self
Chcę dodać jeszcze jedną odpowiedź:
there is difference between parameter and argument
możesz przeczytać szczegółowo o Argumentach i parametrach w Pythoniedef hello(a,b=1, *args): print(a, b, *args) hello(1, 2, 3, 4,a=12)
ponieważ mamy trzy parametry:
a jest parametrem pozycyjnym
b = 1 to słowo kluczowe i parametr domyślny
* args to parametr o zmiennej długości
więc najpierw przypisujemy jako parametr pozycyjny, co oznacza, że musimy podać wartość argumentowi pozycyjnemu w jego kolejności pozycji, tutaj kolejność ma znaczenie. ale przekazujemy argument 1 w miejscu a w wywoływanej funkcji, a następnie przekazujemy również wartość a, traktując ją jako argument słowa kluczowego. teraz a mają dwie wartości:
jeden to wartość pozycyjna: a = 1
druga to wartość ze słowem kluczowym a = 12
Rozwiązanie
Musimy zmienić
hello(1, 2, 3, 4,a=12)
na,hello(1, 2, 3, 4,12)
więc teraz a otrzyma tylko jedną wartość pozycyjną, która wynosi 1, a b otrzyma wartość 2, a reszta wartości otrzyma * args (parametr o zmiennej długości)Dodatkowe informacje
jeśli chcemy, aby * argumenty otrzymały 2,3,4, a a powinno otrzymać 1, a b powinno otrzymać 12
wtedy możemy to zrobić
def hello(a,*args,b=1): pass hello(1, 2, 3, 4,b=12)
Coś więcej :
def hello(a,*c,b=1,**kwargs): print(b) print(c) print(a) print(kwargs) hello(1,2,1,2,8,9,c=12)
wynik :
1 (2, 1, 2, 8, 9) 1 {'c': 12}
źródło
Ten błąd może się również zdarzyć, jeśli przekażesz argument słowa kluczowego, dla którego jeden z kluczy jest podobny (ma tę samą nazwę ciągu) do argumentu pozycyjnego.
>>> 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' >>>
„ogień” został zaakceptowany w argumencie „bar”. A jednak w kwargach występuje inny argument „bar”.
Musiałbyś usunąć argument słowa kluczowego z kwargs przed przekazaniem go do metody.
źródło
Może się to również zdarzyć w Django, jeśli używasz jquery ajax dla adresu URL, który odwraca się do funkcji, która nie zawiera parametru 'request'
$.ajax({ url: '{{ url_to_myfunc }}', }); def myfunc(foo, bar): ...
źródło