首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >使用*args和**kws指定关键字参数

使用*args和**kws指定关键字参数
EN

Stack Overflow用户
提问于 2013-02-02 17:38:51
回答 3查看 4.2K关注 0票数 4

我在Python中发现了一个让我困惑和恼火的行为,我想知道我哪里错了。

我有一个函数,它应该接受任意数量的参数和关键字,但另外应该有一些默认值的关键字,这些关键字构成了它的实际接口:

代码语言:javascript
复制
def foo(my_keyword0 = None, my_keyword1 = 'default', *args, **kws):
    for argument in args:
        print argument

问题是,如果我尝试调用foo(1, 2, 3),我将只得到3的打印输出,并且值1和2将覆盖我的关键字参数。

另一方面,如果我尝试将关键字移到*args**kws之后,将会导致语法错误。对于这个问题,我找到的唯一解决方案是从**kws中提取关键字参数,并为其设置默认值:

代码语言:javascript
复制
def foo(*args, **kws):
    my_keyword0 = None if 'my_keyword0' not in kws else kws.pop('my_keyword0')
    my_keyword0 = 'default' if 'my_keyword1' not in kws else kws.pop('my_keyword1')
    for argument in args:
        print argument

这是可怕的,因为它迫使我添加毫无意义的代码,因为函数签名变得更难理解-你必须实际阅读函数代码,而不是只看它的接口。

我遗漏了什么?有没有更好的方法来做这件事?

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2013-02-02 18:08:02

带有默认值的函数参数仍然是位置参数,因此您看到的结果是正确的。当您为参数指定默认值时,您正在创建关键字参数而不是。当参数不是由函数调用提供时,仅使用默认值。

代码语言:javascript
复制
>>> def some_function(argument="Default"):
...     # argument can be set either using positional parameters or keywords
...     print argument
... 
>>> some_function()    # argument not provided -> uses default value
Default
>>> some_function(5)    # argument provided, uses it
5
>>> some_function(argument=5)    # equivalent to the above one
5
>>> def some_function(argument="Default", *args):
...     print (argument, args)
... 
>>> some_function()   #argument not provided, so uses the default and *args is empty
('Default', ())
>>> some_function(5)   # argument provided, and thus uses it. *args are empty
(5, ())
>>> some_function(5, 1, 2, 3)   # argument provided, and thus uses it. *args not empty
(5, (1, 2, 3))
>>> some_function(1, 2, 3, argument=5)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: some_function() got multiple values for keyword argument 'argument'

注意最后一条错误消息:正如您所看到的,1被分配给argument,然后python再次发现引用argumentkeyword,从而引发了一个错误。只有在分配了所有可能的位置参数之后,才会分配*args

python2中的除了使用 `kwargs`**之外,没有其他方法可以定义只包含关键字的值。作为一种变通办法,您可以执行以下操作:

代码语言:javascript
复制
def my_function(a,b,c,d,*args, **kwargs):
    default_dict = {
        'my_keyword1': TheDefaultValue,
        'my_keyword2': TheDefaultValue2,
    }
    default_dict.update(kwargs)    #overwrite defaults if user provided them
    if not (set(default_dict) <= set('all', 'the', 'possible', 'keywords')):
        # if you want to do error checking on kwargs, even though at that
        # point why use kwargs at all?
        raise TypeError('Invalid keywords')
    keyword1 = default_dict['keyword1']
    # etc.

在python3中,您可以定义仅包含关键字的参数:

代码语言:javascript
复制
def my_function(a,b,c,*args, keyword, only=True): pass
    # ... 

请注意,仅关键字并不意味着它应该具有默认值。

票数 6
EN

Stack Overflow用户

发布于 2013-02-02 18:28:22

在Python中,非关键字参数不能出现在关键字参数之后,因此您尝试使用的函数签名是不可能的:

代码语言:javascript
复制
foo(my_keyword0="baa", my_keyword1="boo", 1, 2, 3, bar="baz", spam="eggs")  # won't work

如果你考虑到这一点,就会有非常充分的理由来解释这个限制(提示:关键字参数可以以任何顺序呈现,而位置参数是...好的,位置)

documentation

在函数调用中,关键字参数必须跟在位置参数之后。传递的所有关键字参数必须与函数接受的参数之一匹配(例如,actor不是parrot函数的有效参数),并且它们的顺序并不重要。这也包括非可选参数

*args**kwargs包含与现有形参不匹配的实参,因此一旦在实参列表中定义了spam=None,它就不会再传递给**kwargs

当出现name形式的最后一个形式参数时,它会接收一个字典(请参阅映射类型-字典),其中包含所有关键字参数**,但与形式参数对应的关键字参数除外。这可以与*name形式的形式参数(在下一小节中描述)结合使用,该参数接收一个包含形式参数列表之外的位置参数的元组。(*name必须在**name之前)

与您的(不可能的)语法最接近的语法如下所示

代码语言:javascript
复制
def foo(my_keyword0=None, my_keyword1='default', numbers=None, **kwargs)

,您将使用它作为

代码语言:javascript
复制
foo(my_keyword0="bar", my_keyword1="baz", numbers=(1,2,3), spam='eggs')
foo("bar", "baz", numbers=(1,2,3))
foo("bar", "baz", (1,2,3))
foo("bar", "baz", (1,2,3), spam="eggs")
foo(numbers=(1,2,3))
foo(spam="eggs")
etc.

可以说,这可能比你最初的想法更具可读性,更不令人惊讶。

票数 3
EN

Stack Overflow用户

发布于 2013-02-02 17:44:08

代码语言:javascript
复制
def foo(my_keyword0 = None, my_keyword1 = 'default', *args, **kws):
    all_args = [my_keyword0, my_keyword1] + args + kws.values()
    for argument in all_args:
        print argument
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/14660541

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档