类方法生成“ TypeError: ... 得到关键字参数的多个值...”

如果我定义一个带有关键字参数的类方法:

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'

发生什么事了?

160555 次浏览

问题在于,传递给 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")时,将使用参数 (myfoo, thing="something")调用 foodo方法。然后将实例 myfoo分配给 thing(因为 thing是第一个声明的参数) ,但 python 也尝试将 "something"分配给 thing,因此产生了 Exception。

要进行演示,请尝试使用原始代码运行此命令:

myfoo.foodo("something")
print
print myfoo

你会输出这样的结果:

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


<__main__.foo object at 0x321c290>

您可以看到,‘ thing’被分配了一个对‘ foo’类的实例‘ myfoo’的引用。文档的 这部分多解释了函数参数是如何工作的。

谢谢你的指导性帖子。我只是想提醒一下,如果你得到“ TypeError: foodo ()为关键字参数‘ thing’得到了多个值”,这也可能是你在调用函数时错误地将‘ self’作为参数传递(可能是因为你从类声明中复制了这一行——这是一个常见的错误,当你匆忙的时候)。

这可能是显而易见的,但它可能会帮助一些人谁从来没有见过它。如果错误地按位置和显式地按名称分配参数,则常规函数也会出现这种情况。

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

只要在函数中添加“ staticmethod”修饰符,问题就解决了

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

如果您使用 jquery ajax 来反转到不包含“ request”参数的函数,那么在 Django 中也会发生这种情况

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




def myfunc(foo, bar):
...

我想再补充一个答案:

当您试图以错误的方式传递位置参数时,就会发生这种情况 调用函数中的位置顺序和关键字参数。

你可以在这里详细阅读

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




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

因为我们有三个参数:

A 是位置参数

B = 1是关键字和缺省参数

* args 是可变长度参数

所以我们首先把 a 赋值为位置参数,意味着我们必须按照它的位置顺序,给位置参数赋值,这里是顺序问题。 但是我们在调用函数的位置传递了参数1,然后我们还给一个关键字参数提供了值。 现在 a 有两个值:

一个是位置值: a = 1

第二个是关键字值 a = 12

解决方案

我们必须把 hello(1, 2, 3, 4,a=12)改成 hello(1, 2, 3, 4,12) 所以现在 a 将只得到一个位置值,即1,b 将得到值2,其余的值将得到 * args (可变长度参数)

额外资料

如果我们想要 * args 应该得到2,3,4,a 应该得到1,b 应该得到12

然后我们可以这样做
Def hello (a,* args,b = 1) : 通过 你好(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}

如果传递的关键字参数的其中一个键与位置参数相似(具有相同的字符串名称) ,也可能发生此错误。

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

在将关键字参数传递给方法之前,必须从 kwargs 中删除它。