метод класу генерує "TypeError: ... отримано кілька значень для аргументу ключового слова ..."


129

Якщо я визначаю метод класу з аргументом ключового слова таким чином:

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

виклик методу генерує TypeError:

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

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

Що відбувається?


1
Ви ніколи не отримаєте задовільної відповіді на те, чому явне selfкраще, ніж неявне this.
Нуреттін

Відповіді:


163

Проблема полягає в тому, що перший аргумент, переданий методам класу в python, завжди є копією екземпляра класу, на якому називається метод, як правило, позначений міткою self. Якщо клас оголошено таким чином:

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

він поводиться так, як очікувалося.

Пояснення:

Без selfпершого параметра, коли myfoo.foodo(thing="something")виконується, foodoметод викликається аргументами (myfoo, thing="something"). myfooПотім присвоюється екземпляр thing(оскільки thingце перший оголошений параметр), але python також намагається призначити "something"його thing, отже, Виняток.

Для демонстрації спробуйте виконати це з оригінальним кодом:

myfoo.foodo("something")
print
print myfoo

Ви отримаєте:

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

<__main__.foo object at 0x321c290>

Ви можете бачити, що "thing" було призначено посиланням на екземпляр "myfoo" класу "foo". Цей розділ Документів пояснює, як аргументи функцій працюють трохи більше.


1
Зверніть увагу: ви можете отримати однотипний помилку, якщо ваша функція def включає self як перший параметр, а потім ви випадково викликаєте функцію також з self як перший параметр.
Крістофер Хантер

48

Дякую за повчальні пости. Я просто хотів би зауважити, що якщо ви отримуєте "TypeError: foodo () отримано кілька значень для аргументу ключового слова" річ "", можливо, ви помилково передаєте "self" як параметр, коли виклик функції (можливо, тому, що ви скопіювали рядок із декларації класу - це звичайна помилка, коли хтось поспішає).


7
Саме це і сталося зі мною, дякую, що додав до цієї відповіді. Це може бути найпоширеніша помилка, через яку ви отримуєте мою нагороду.
rdrey

Те ж саме відбувається , коли перевантаження @classmethod, то рішення в тому , щоб використовувати super().function(...)замість <parentclass>.function(cls, ...).
едераг

30

Це може бути очевидним, але це може допомогти тому, хто ніколи цього не бачив. Це також відбувається для звичайних функцій, якщо ви помилково призначили параметр за позицією та явно по імені.

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

просто додайте декоратор 'staticmethod', щоб функціонувати, і проблема виправлена

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

Я щойно отримав цю помилку, і це рішення вирішило мою проблему. Але чи можете ви детальніше розповісти, як чи чому цей декоратор вирішив проблему?
Рей

1
staticmethod зупиняє метод отримання self в якості першого аргументу. Отже, якщо ви зателефонуєте myfoo.foodo(thing="something"), перше аргумент буде присвоєно thing = "щось", а не неявний аргумент.
danio

це також означає, що ви не можете отримати доступ до змінних класу в межах функції, до яких зазвичай можна отримати доступself
drevicko

4

Я хочу додати ще одну відповідь:

Це трапляється, коли ви намагаєтеся передати позиційний параметр із неправильним порядком позиції разом із аргументом ключового слова у функції виклику.

there is difference between parameter and argumentВи можете детально прочитати тут Аргументи та параметр у python

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


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

оскільки у нас є три параметри:

a - позиційний параметр

b = 1 - це ключове слово та параметр за замовчуванням

* args - параметр змінної довжини

тому ми спочатку призначаємо як позиційний параметр, це означає, що ми повинні надати значення позиційному аргументу у його позиційному порядку, тут порядок має значення. але ми передаємо аргумент 1 на місце функції виклику, і тоді ми також надаємо значення a, трактуючи як аргумент ключового слова. тепер у a є два значення:

одне - позиційне значення: a = 1

друге - ключове слово, яке є = 12

Рішення

Ми повинні змінитись, hello(1, 2, 3, 4,a=12)щоб hello(1, 2, 3, 4,12) тепер a отримає лише одне позиційне значення, яке дорівнює 1, а b отримає значення 2, а решта значень отримають * args (параметр змінної довжини)

Додаткова інформація

якщо ми хочемо, щоб * аргументи мали отримати 2,3,4, а a - 1, b - 12

тоді ми можемо зробити так
def hello(a,*args,b=1): pass hello(1, 2, 3, 4,b=12)

Щось більше :

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

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

вихід:

1

(2, 1, 2, 8, 9)

1

{'c': 12}

це вже охоплено відповіддю stackoverflow.com/a/31822875/12663 - у вашому прикладі є той самий параметр (a), призначений за позицією, а також явно по імені.
danio

3

Ця помилка також може статися, якщо ви передасте аргумент ключового слова, для якого один з ключів схожий (має таку ж назву рядка) позиційному аргументу.

>>> 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'
>>> 

"пожежа" була прийнята в аргумент "бар". І все ж є ще один «барний аргумент», присутній у кваргів.

Вам доведеться видалити аргумент ключового слова з kwargs, перш ніж передавати його методу.


1

Також це може статися в Django, якщо ви використовуєте jquery ajax для URL, який переходить до функції, яка не містить параметра "запит"

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


def myfunc(foo, bar):
    ...
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.