【问题标题】:class method generates "TypeError: ... got multiple values for keyword argument ..."类方法生成“TypeError:...为关键字参数获取多个值...”
【发布时间】:2013-09-27 19:21:23
【问题描述】:

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

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'

发生了什么事?

【问题讨论】:

  • 对于为什么显式 self 比隐式 this 更好,您永远不会得到满意的答案。

标签: python class python-2.7 methods


【解决方案1】:

问题是传递给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”已被分配了对“foo”类的实例“myfoo”的引用。文档的This section 解释了函数参数的工作原理。

【讨论】:

  • 注意:如果你的函数 def 包含 self 作为第一个参数,你可能会得到相同类型的错误,然后你不小心调用了这个函数并且 self 作为第一个参数。
【解决方案2】:

感谢您的指导性帖子。我想提醒一下,如果您收到“TypeError: foodo() got multiple values for keyword argument 'thing'”,也可能是您错误地将 'self' 作为参数传递时调用函数(可能是因为您从类声明中复制了该行 - 这是一个匆忙时的常见错误)。

【讨论】:

  • 这就是发生在我身上的事情,感谢您添加到这个答案。这可能是更常见的错误,这就是为什么你得到我的支持。
  • 重载@classmethod 时也会发生同样的情况,solution 使用super().function(...) 而不是&lt;parentclass&gt;.function(cls, ...)
【解决方案3】:

这可能很明显,但它可能对从未见过它的人有所帮助。如果您错误地按位置和显式地按名称分配参数,常规函数也会发生这种情况。

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

【讨论】:

    【解决方案4】:

    只需将“staticmethod”装饰器添加到函数中即可解决问题

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

    【讨论】:

    • 我刚收到这个错误,这个解决方案解决了我的问题。但是你能详细说明这个装饰器是如何或为什么解决这个问题的吗?
    • staticmethod 停止接收 self 作为第一个参数的方法。所以现在,如果你调用myfoo.foodo(thing="something"),thing="something" 将被分配给第一个参数,而不是隐含的 self 参数。
    • 也表示不能访问函数内的类变量,一般通过self访问
    【解决方案5】:

    如果您使用 jquery ajax 到 url 反转到不包含“请求”参数的函数,这也可能在 Django 中发生

    $.ajax({
      url: '{{ url_to_myfunc }}',
    });
    
    
    def myfunc(foo, bar):
        ...
    

    【讨论】:

      【解决方案6】:

      我想再补充一个答案:

      当您尝试传递错误的位置参数时会发生这种情况 调用函数中的位置顺序以及关键字参数。

      there is difference between parameter and argument你可以在这里详细阅读Arguments and Parameter in 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 有两个值:

      一个是位置值:a=1

      second 是关键字值,即 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): 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}
      

      【讨论】:

      【解决方案7】:

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

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

      "fire" 已被 'bar' 参数接受。然而,在 kwargs 中还有另一个 'bar' 论点。

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

      【讨论】:

        猜你喜欢
        • 2017-07-14
        • 2016-04-25
        • 1970-01-01
        • 1970-01-01
        • 2018-04-22
        • 2017-06-27
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多