传递函数调用的参数的Python排序规则
我尝试使用*和**将任意数量的参数传递给函数。在Mark Lutz撰写的《学习Python》一书中,它说首先要遵循位置(值)的顺序,然后是关键字参数(name=value)和*序列的组合,然后是**dict。然而,我发现如果存在位置参数,则必须首先出现,但在一定程度上,其余三个参数可以按顺序混合传递函数调用的参数的Python排序规则,python,Python,我尝试使用*和**将任意数量的参数传递给函数。在Mark Lutz撰写的《学习Python》一书中,它说首先要遵循位置(值)的顺序,然后是关键字参数(name=value)和*序列的组合,然后是**dict。然而,我发现如果存在位置参数,则必须首先出现,但在一定程度上,其余三个参数可以按顺序混合 代码关键字3.py: def func(a, b=1, *pArgs, **kwArgs): print("a = {0}, b = {1}".format(a,b))
代码关键字3.py:
def func(a, b=1, *pArgs, **kwArgs):
print("a = {0}, b = {1}".format(a,b))
print("Positional args = {}".format(pArgs))
print("Keyword args = {}".format(kwArgs))
经过反复试验
[1] 在关键字和**dict之间,它们可以是任意顺序
>>> import keywords3 as j
>>> j.func(b = 3, **{'a':2,'c':4,'d':5})
a = 2, b = 3
Positional args = ()
Keyword args = {'d': 5, 'c': 4}
>>> j.func( **{'a':2}, b = 3, **{'c':4})
a = 2, b = 3
Positional args = ()
Keyword args = {'c': 4}
>>> j.func(*(2, 3), 4, *(5, 6))
a = 2, b = 3
Positional args = (4, 5, 6)
Keyword args = {}
>>> j.func(2, *(3, 4), 5, *(6,7), **{'c':8})
a = 2, b = 3
Positional args = (4, 5, 6, 7)
Keyword args = {'c': 8}
[2] 在位置参数和*序列之间,它们可以是任意顺序
>>> import keywords3 as j
>>> j.func(b = 3, **{'a':2,'c':4,'d':5})
a = 2, b = 3
Positional args = ()
Keyword args = {'d': 5, 'c': 4}
>>> j.func( **{'a':2}, b = 3, **{'c':4})
a = 2, b = 3
Positional args = ()
Keyword args = {'c': 4}
>>> j.func(*(2, 3), 4, *(5, 6))
a = 2, b = 3
Positional args = (4, 5, 6)
Keyword args = {}
>>> j.func(2, *(3, 4), 5, *(6,7), **{'c':8})
a = 2, b = 3
Positional args = (4, 5, 6, 7)
Keyword args = {'c': 8}
[3] 通常,位置或*序列参数需要出现在关键字或**dict参数之前
>>> j.func(*(3, 4), 5, *(6,7), d=15, **{'c':8}, e=16)
a = 3, b = 4
Positional args = (5, 6, 7)
Keyword args = {'e': 16, 'd': 15, 'c': 8}
>>> j.func(d=15, 5, *(6,7), **{'c':8}, e=16)
File "<stdin>", line 1
SyntaxError: positional argument follows keyword argument
>>> j.func(**{'a':2}, 5, *(6,7), **{'c':8}, e=16)
File "<stdin>", line 1
SyntaxError: positional argument follows keyword argument unpacking
>>> j.func(**{'a':2}, *(6,7), **{'c':8}, e=16)
File "<stdin>", line 1
SyntaxError: iterable argument unpacking follows keyword argument unpacking
这些观察结果正确吗?请发表评论。有一条规则与所有示例一致:位置参数在命名参数之前
>>> j.func(*(3, 4), 5, *(6,7), d=15, **{'c':8}, e=16)
a = 3, b = 4
Positional args = (5, 6, 7)
Keyword args = {'e': 16, 'd': 15, 'c': 8}
>>> j.func(d=15, 5, *(6,7), **{'c':8}, e=16)
File "<stdin>", line 1
SyntaxError: positional argument follows keyword argument
>>> j.func(**{'a':2}, 5, *(6,7), **{'c':8}, e=16)
File "<stdin>", line 1
SyntaxError: positional argument follows keyword argument unpacking
>>> j.func(**{'a':2}, *(6,7), **{'c':8}, e=16)
File "<stdin>", line 1
SyntaxError: iterable argument unpacking follows keyword argument unpacking
在所有示例中,*
和***
都是解包运算符。比如说,当你写作的时候
f(1, *(2,3), 4)
语言越来越流行
f(1,2,3,4)
它们都是位置参数,语言不知道它们的区别。对于**
操作符也是如此
然而,当你违反了唯一的规则,例如
j.func(**{'a':2}, 5, *(6,7), **{'c':8}, e=16)
您会得到一个错误,因为在本例中,
**{'a':2}
相当于a=2
,它位于位置参数5
之前。语法规则在以下位置可用:您混淆了函数调用时发生的列表/字典解包,以及定义函数时使用的参数列表/字典。两者使用相同的符号(*和**),但含义完全不同。例如,f(*(1,2,3)
扩展为f(1,2,3)
。1和2仍然是位置参数。同样地,f(**{'c':8},e=16)
变成了f(c=8,e=16)
,两个命名参数。不完全一样f(a=1,*b)
在a*
解包之前有一个关键字参数,但这是允许的。它的意思与更直观的f(*b,a=1)
,以及f(*b,a=1)
过去被禁止的意思相同。谢谢大家的精彩解释。@user2357112关于f(a=1,*b)被允许的说法是我在[4]异常中观察到的。与f(**a,*b)相比,f(**a,*b)是由于“单一规则”而不允许的,这种类型违反了单一规则。是吗?@LeonChang:语言必须知道哪个值对应哪个变量。在本例中,它起作用是因为您的命名参数恰好是第一个参数。尽管如此,我还是认为这会产生一个错误(我敢打赌,许多其他python程序员也是如此)。不管什么是有效的,可读性很重要,所以不要这样做。当函数真正接受项集合时,请使用*
;当您确实有来自其他函数的类似dict/json的对象时,请使用**
。避免同时使用这两种方法,在大多数情况下,两种方法都不要使用。