[英]Confusion with Python functions using an argument, keyword argument, *args, **kwargs
Given the below function and resulting calls to print_stuff()
, can someone explain why there is unexpected behavior when calling the function without a keyword arg default but passing in a list to *args
? 鉴于以下函数和对
print_stuff()
调用,有人可以解释为什么在没有关键字arg默认但是将列表传递给*args
情况下调用函数时会出现意外行为吗?
I'm aware of the "gotcha" involving mutable/immutable keyword defaults, but I don't see that being relevant here. 我知道涉及mutable / immutable关键字默认值的“gotcha”,但我不认为这里有相关性。
Can someone clarify why this occurs, or any syntax/invocation error? 有人可以澄清为什么会发生这种情况,或任何语法/调用错误?
def print_stuff(arg, kwarg=None, *args):
print "arg: %s" % arg
if kwarg:
print "kwarg: %s" % kwarg
if args:
for a in args:
print "printing {} from args".format(a)
print "===end==="
args_list = range(1, 3)
kwargs_list = {str(a):a for a in args_list}
print_stuff('hi', kwarg='some_kwarg') # works as intended
print_stuff('hi', 'some_kwarg', *range(1, 3)) # also works as intended
print_stuff('hi', *range(1, 3)) # first element of list unexpectedly passed in to keyword argument, even using the * notation
print_stuff('hi', kwarg='some_kwarg', *range(1, 3)) # TypeError: print_stuff() got multiple values for keyword argument 'kwarg'
kwarg
is not a keyword-only argument; kwarg
不是仅限关键字的参数; it's just a positional argument that has a default. 它只是一个具有默认值的位置参数。 Your call
您的来电
print_stuff('hi', *range(1,3))
is exactly the same as 与...完全相同
print_stuff('hi', 1, 2)
which assigns the first two arguments to the first two named parameters, and the remaining (ie, the third) is placed in the *args
parameter. 它将前两个参数分配给前两个命名参数,剩下的(即第三个)放在
*args
参数中。
Aside from having a default value for kwarg
, print_stuff(arg, kwarg=None, *args)
is no different to print_stuff(arg, kwarg, *args)
- if there is a second positional argument, it is passed as the kwarg
parameter (any subsequent positional arguments end up in args
). 除了拥有
kwarg
的默认值kwarg
, print_stuff(arg, kwarg=None, *args)
与print_stuff(arg, kwarg, *args)
没什么区别 - 如果有第二个位置参数,它将作为kwarg
参数传递(任何后续的位置参数都以args
结尾。
Note that: 注意:
print_stuff('hi', *range(1, 3))
is evaluated as: 被评估为:
print_stuff('hi', 1, 2)
so the first argument goes to arg
, the second goes to kwarg
and the third to args[0]
. 所以第一个参数是
arg
,第二个参数是kwarg
,第三个args[0]
。
Then if we note that: 然后,如果我们注意到:
print_stuff('hi', kwarg='some_kwarg', *range(1, 3))
is equivalent to: 相当于:
print_stuff('hi', *range(1, 3), kwarg='some_kwarg')
and therefore to: 因此:
print_stuff('hi', 1, 2, kwarg='some_kwarg')
you can perhaps see the problem - again 'hi'
, 1
and 2
go to arg
, kwarg
and args[0]
respectively but then another value for kwarg
turns up unexpectedly. 你也许可以看到问题 - 再次
'hi'
, 1
和2
转到arg
, kwarg
和args[0]
但是kwarg
另一个值意外地出现了。
If you want all positional arguments to be "soaked up" before kwarg
is considered, change the function definition to: 如果您希望在考虑
kwarg
之前 “吸收”所有位置参数,请将函数定义更改为:
def print_stuff(arg, *args, **kwargs):
print "arg: %s" % arg
kwarg = kwargs.get('kwarg')
if kwarg is not None: # note explicit test - what if kwarg == 0?
print "kwarg: %s" % kwarg
for a in args: # no need to test here - loop doesn't run if no args
print "printing {} from args".format(a)
print "===end==="
In use: 正在使用:
>>> print_stuff('hi', *range(1, 3))
arg: hi
printing 1 from args
printing 2 from args
===end===
>>> print_stuff('hi', *range(1, 3), kwarg='some_kwarg')
arg: hi
kwarg: some_kwarg
printing 1 from args
printing 2 from args
===end===
Note that in 3.x you can have keyword-only arguments , ie the following is an alternative: 请注意,在3.x中,您可以使用仅限关键字的参数 ,即以下是替代方法:
def print_stuff(arg, *args, kwarg=None):
...
One simple way to think of it is this: 想到它的一个简单方法是:
When an argument is passed to a function, it gets added to a positional argument "queue" of sorts. 当一个参数传递给一个函数时,它会被添加到各种位置参数“队列”中。 Python will ignore keyword arguments and prioritize non-keyword arguments when assigning to this queue.
在分配给此队列时,Python将忽略关键字参数并确定非关键字参数的优先级。 All keyword arguments are assigned last in function calls.
所有关键字参数都在函数调用中最后分配。 You can imagine this as Python "shifting around the order" of your arguments because its eager to fill positions first.
你可以想象这是因为Python渴望首先填补位置,因此Python会“改变你的论点”。 So with a call like:
所以通过以下呼叫:
print_stuff('hi', kwarg='some_kwarg', *range(1,3))
Python will basically transform it into: Python基本上将它转换为:
print_stuff('hi', 1, 2, kwarg='some_kwarg')
and then will get angry because you assign to kwarg twice. 因为你两次分配给kwarg会生气。
***Note that this is not necessarily what actually happens, but it's a good way of thinking about it because you will be able to handle mistakes and can also explain why in a call like: ***请注意,这不一定是实际发生的事情,但它是一种思考它的好方法,因为你将能够处理错误,并且还可以解释为什么在一个调用中:
print_stuff('hi', *range(1,3))
the 1 gets passed to the 2nd positional argument kwarg, and the 2 gets passed to the 3rd argument args. 1传递给第二个位置参数kwarg,2传递给第三个参数args。
Simply i am writing a function to show how *args
and **kwargs
works 我只是编写一个函数来展示
*args
和**kwargs
是如何工作的
def test_function(normal_arg, *arg, **kwargs):
print(locals())
return
test_function("normal_arg-value",
"*arg1-value", "*arg2-value",
karg1="karg1-value", karg2="karg2-value")
#output
{'arg1': 'arg1-value', 'arg': ('*arg1-value', '*arg2-value'), 'kwargs': {'karg2': 'karg2-value', 'karg1': 'karg1-value'}}
Hope this helps. 希望这可以帮助。
How unlimited of arguments can pass to a function 参数的无限制可以传递给函数
def test(*lis):
print locals()
test(1,2,3)
#output
{'lis': (1, 2, 3)}
How unlimited named arguments can pass to a function 无限名称参数如何传递给函数
def test(**dicts):
print locals()
test(arg1="value1", arg2="value2")
#output
{'dicts': {'arg1': 'value1', 'arg2': 'value2'}}
How a dictionary pass to a function as argument 字典如何作为参数传递给函数
def test(**dicts):
print locals()
test(**{"arg1":"value1", "arg2": "value2"})
#output
{'dicts': {'arg1': 'value1', 'arg2': 'value2'}}
Hope this helps you 希望这对你有所帮助
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.