如果存在相同名称的位置参数,为什么kwargs中的键被删除



我刚刚遇到了这个让我惊讶的行为:

def my_func(a=4, **kwargs):
    print kwargs
演示:

>>> my_func(a=5, b=6)
{'b': 6}  # I was expecting {'a' : 4, 'b' : 6}
          # Maybe {'a' : 5, 'b' : 6}

同样,如果我得到:

我也不会感到惊讶。

SyntaxError: keyword argument repeated

>>> my_func(a=4, a=5)
  File "<stdin>", line 1
SyntaxError: keyword argument repeated

TypeError: my_func() got multiple values for keyword argument 'a'

>>> my_func(a=4, **{'a' : 5, 'b' : 6})
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: my_func() got multiple values for keyword argument 'a'

python遵循什么规则来删除关键字'a'?

也许我遗漏了一些明显的东西,或者一个关键的术语,但我无法通过搜索找到解决方案。

a没有被删除,它只是没有被包含在**kwargs中,因为您在函数定义中明确定义了它。所以如果我编辑你原来的例子:

def my_func(a=4, **kwargs):
    print kwargs
    print a

然后测试:

>>> my_func(a=5, b=7)
{'b': 7}
5

**kwargs参数用于收集函数调用中给出的可选关键字参数,这些参数未显式包含在函数定义中。由于您在my_func的定义中包含了a=4,因此它不会包含在**kwargs中。

Python文档中提到了这一点(强调我的):

当出现**name形式的最终形式参数时接收一个包含所有类型的字典(参见映射类型-字典)关键字参数与形式形参对应的参数除外。

似乎Python的实参到形参的映射包括处理任何以"arg=value"表达式表示的实参,即使它们是无序的。这将从**kwargs字典中删除"arg=value"对(该字典捕获不在参数列表中的所有名称/键)。

考虑这个简单的例子:

#/usr/bin/python
def foo(a, **d):
    print 'a=', a
    print 'd=', d
foo(z=1)
## TypeError: foo() takes exactly 1 argument (0 given)
foo(a=1)
## a= 1
## d= {}
foo(z=1, a=2, b=3)
## a= 2
## d= {'z':1, 'b':3}
foo(a=1, z=2, 3)
## SyntaxError: non-keyword arg after keyword arg

注意,我已经用位置形参实现了"foo",并且没有默认实参;它有一个默认值,那么"a="仍然会从参数列表中被挑选出来,如果它出现了,但它的遗漏不会引发异常,它将是"None"或任何你提供的默认参数。

有时区分实参和形参是有用的。这种区别很少在普通文档和在线讨论中得到遵守。所以这可能有点学术性。然而,形参是一个名称,在函数的定义/头文件中提供,在调用函数时将实参绑定到该名称中。参数=占位符,参数=调用期间的实际值。有时候,做出这样的区分可以使讨论,比如这个讨论,不那么令人困惑。

在讨论def语句本身时,可能会产生一点混淆。在我的语句中:def foo(a=None, **d) a和d是参数,而a=None**d是参数(定义语句本身)。当中级Python程序员第一次遇到在函数定义中作为参数实例化的可变对象的语义时,这可能特别令人困惑:def foo(mydict={}, mylist=[]):…当带参数和不带参数调用时,这可能会有一些有趣的语义。理解这类函数的关键是mydict和mylist绑定到定义函数时实例化的对象。这些对象只有在函数调用时不带参数时才可见,当函数调用时带参数时,这些参数被绑定到其他对象上。(正如您所看到的,当将术语"参数"与"参数"互换使用时,这个概念几乎无法表达)。

最新更新