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

问题描述 投票:0回答:8

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

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'

发生什么事了?

python class python-2.7 methods
8个回答
175
投票

问题在于,传递给 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”的引用。 文档的这一部分进一步解释了函数参数的工作原理。


52
投票

感谢您的指导性帖子。我只是想注意一下,如果您收到“TypeError:foodo() 获得关键字参数“thing”的多个值”,也可能是您在以下情况下错误地将“self”作为参数传递:调用函数(可能是因为您从类声明中复制了该行 - 这是匆忙时的常见错误)。


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'

8
投票

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

>>> 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 中删除关键字参数。


6
投票

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

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

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 是变长参数

所以我们首先将 a 指定为位置参数,这意味着我们必须按照位置顺序为位置参数提供值,这里顺序很重要。 但是我们在调用函数时在 a 的位置传递参数 1,然后我们也向 a 提供值,将其视为关键字参数。 现在 a 有两个值:

one 为位置值: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):
     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}

1
投票

如果您使用 jquery ajax 来返回不包含“请求”参数的函数的 url,这种情况也可能发生在 Django 中

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


def myfunc(foo, bar):
    ...

0
投票

问题的另一个来源是与 kwargs 和传递函数取消对齐时。我错误地在

write_to_dataset
中的 kwargs 中设置了 file_options,这是一个创建
file_options
并调用
write_dataset(file_options=file_options, **kwargs)
的包装函数。

在这种情况下,有两个 file_options 被传递,一个从顶层调用到

write_to_dataset(fileoptions=<>)
,它馈送到
write_data_set
kwargs 和一个新的 file_options 调用。

对于那些好奇的人,这是来自 pyarrow:

mywrite = write_to_dataset(file_options=<>, ...)

def write_to_dataset(table, root_path, partition_cols=None,
                     partition_filename_cb=None, filesystem=None,
                     use_legacy_dataset=None, schema=None,
                     partitioning=None, basename_template=None,
                     use_threads=None, file_visitor=None,
                     existing_data_behavior=None,
                     **kwargs):
        write_dataset_kwargs['max_rows_per_group'] = kwargs.pop(
            'row_group_size', kwargs.pop("chunk_size", None)
        parquet_format = ds.ParquetFileFormat()
        write_options = parquet_format.make_write_options(**kwargs)

        ds.write_dataset(
            ...file_options=write_options,
            ...
            **write_dataset_kwargs)

write_dataset_kwargs 最终在 file_options=write_options 行之上有一个 file_options

© www.soinside.com 2019 - 2024. All rights reserved.