使用参数、关键字参数、*args、**kwargs 与 Python 函数混淆
Confusion with Python functions using an argument, keyword argument, *args, **kwargs
鉴于以下函数和对 print_stuff()
的结果调用,有人可以解释为什么在调用没有关键字 arg default 的函数但将列表传递给 *args
时出现意外行为吗?
我知道 "gotcha" 涉及 mutable/immutable 关键字默认值,但我认为这与此处无关。
有人可以解释为什么会发生这种情况,或者任何 syntax/invocation 错误吗?
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
不是仅关键字参数;它只是一个有默认值的位置参数。您的来电
print_stuff('hi', *range(1,3))
与
完全相同
print_stuff('hi', 1, 2)
它将前两个参数赋值给前两个命名参数,其余(即第三个)放在*args
参数中。
除了 kwarg
的默认值外,print_stuff(arg, kwarg=None, *args)
与 print_stuff(arg, kwarg, *args)
没有什么不同 - 如果有第二个位置参数,它将作为 [=18= 传递] 参数(任何后续位置参数都以 args
结尾)。
注意:
print_stuff('hi', *range(1, 3))
被评估为:
print_stuff('hi', 1, 2)
所以第一个参数转到 arg
,第二个转到 kwarg
,第三个转到 args[0]
。
那么如果我们注意到:
print_stuff('hi', kwarg='some_kwarg', *range(1, 3))
相当于:
print_stuff('hi', *range(1, 3), kwarg='some_kwarg')
因此:
print_stuff('hi', 1, 2, kwarg='some_kwarg')
您也许可以看到问题 - 再次 'hi'
、1
和 2
分别转到 arg
、kwarg
和 args[0]
但是 kwarg
的另一个 值意外出现。
如果你希望所有位置参数在"soaked up" 之前 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==="
正在使用中:
>>> 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===
请注意,在 3.x 中,您可以使用 keyword-only arguments,即以下是替代方案:
def print_stuff(arg, *args, kwarg=None):
...
一个简单的想法是这样的:
当一个参数被传递给一个函数时,它被添加到一个位置参数 "queue" 之类的。 Python 将忽略关键字参数并在分配给此队列时优先考虑非关键字参数。在函数调用中,所有关键字参数都被赋值为 last。你可以把它想象成你的论点 Python "shifting around the order" 因为它急于先填补职位。所以用这样的电话:
print_stuff('hi', kwarg='some_kwarg', *range(1,3))
Python基本上会转化为:
print_stuff('hi', 1, 2, kwarg='some_kwarg')
然后会因为你给kwarg赋值两次而生气
***请注意,这不一定是 实际发生的,但这是一种很好的思考方式,因为您将能够处理错误并解释原因在这样的电话中:
print_stuff('hi', *range(1,3))
1 被传递给第二个位置参数 kwarg,2 被传递给第三个参数 args。
只是我正在编写一个函数来展示 *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'}}
希望对您有所帮助。
如何将无限的参数传递给函数
def test(*lis):
print locals()
test(1,2,3)
#output
{'lis': (1, 2, 3)}
如何将无限制的命名参数传递给函数
def test(**dicts):
print locals()
test(arg1="value1", arg2="value2")
#output
{'dicts': {'arg1': 'value1', 'arg2': 'value2'}}
字典如何作为参数传递给函数
def test(**dicts):
print locals()
test(**{"arg1":"value1", "arg2": "value2"})
#output
{'dicts': {'arg1': 'value1', 'arg2': 'value2'}}
希望对您有所帮助
鉴于以下函数和对 print_stuff()
的结果调用,有人可以解释为什么在调用没有关键字 arg default 的函数但将列表传递给 *args
时出现意外行为吗?
我知道 "gotcha" 涉及 mutable/immutable 关键字默认值,但我认为这与此处无关。
有人可以解释为什么会发生这种情况,或者任何 syntax/invocation 错误吗?
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
不是仅关键字参数;它只是一个有默认值的位置参数。您的来电
print_stuff('hi', *range(1,3))
与
完全相同print_stuff('hi', 1, 2)
它将前两个参数赋值给前两个命名参数,其余(即第三个)放在*args
参数中。
除了 kwarg
的默认值外,print_stuff(arg, kwarg=None, *args)
与 print_stuff(arg, kwarg, *args)
没有什么不同 - 如果有第二个位置参数,它将作为 [=18= 传递] 参数(任何后续位置参数都以 args
结尾)。
注意:
print_stuff('hi', *range(1, 3))
被评估为:
print_stuff('hi', 1, 2)
所以第一个参数转到 arg
,第二个转到 kwarg
,第三个转到 args[0]
。
那么如果我们注意到:
print_stuff('hi', kwarg='some_kwarg', *range(1, 3))
相当于:
print_stuff('hi', *range(1, 3), kwarg='some_kwarg')
因此:
print_stuff('hi', 1, 2, kwarg='some_kwarg')
您也许可以看到问题 - 再次 'hi'
、1
和 2
分别转到 arg
、kwarg
和 args[0]
但是 kwarg
的另一个 值意外出现。
如果你希望所有位置参数在"soaked up" 之前 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==="
正在使用中:
>>> 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===
请注意,在 3.x 中,您可以使用 keyword-only arguments,即以下是替代方案:
def print_stuff(arg, *args, kwarg=None):
...
一个简单的想法是这样的:
当一个参数被传递给一个函数时,它被添加到一个位置参数 "queue" 之类的。 Python 将忽略关键字参数并在分配给此队列时优先考虑非关键字参数。在函数调用中,所有关键字参数都被赋值为 last。你可以把它想象成你的论点 Python "shifting around the order" 因为它急于先填补职位。所以用这样的电话:
print_stuff('hi', kwarg='some_kwarg', *range(1,3))
Python基本上会转化为:
print_stuff('hi', 1, 2, kwarg='some_kwarg')
然后会因为你给kwarg赋值两次而生气
***请注意,这不一定是 实际发生的,但这是一种很好的思考方式,因为您将能够处理错误并解释原因在这样的电话中:
print_stuff('hi', *range(1,3))
1 被传递给第二个位置参数 kwarg,2 被传递给第三个参数 args。
只是我正在编写一个函数来展示 *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'}}
希望对您有所帮助。
如何将无限的参数传递给函数
def test(*lis):
print locals()
test(1,2,3)
#output
{'lis': (1, 2, 3)}
如何将无限制的命名参数传递给函数
def test(**dicts):
print locals()
test(arg1="value1", arg2="value2")
#output
{'dicts': {'arg1': 'value1', 'arg2': 'value2'}}
字典如何作为参数传递给函数
def test(**dicts):
print locals()
test(**{"arg1":"value1", "arg2": "value2"})
#output
{'dicts': {'arg1': 'value1', 'arg2': 'value2'}}
希望对您有所帮助