繁体   English   中英

使用参数,关键字参数,* args,** kwargs与Python函数混淆

[英]Confusion with Python functions using an argument, keyword argument, *args, **kwargs

鉴于以下函数和对print_stuff()调用,有人可以解释为什么在没有关键字arg默认但是将列表传递给*args情况下调用函数时会出现意外行为吗?

我知道涉及mutable / immutable关键字默认值的“gotcha”,但我不认为这里有相关性。

有人可以澄清为什么会发生这种情况,或任何语法/调用错误?

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的默认值kwargprint_stuff(arg, kwarg=None, *args)print_stuff(arg, kwarg, *args)没什么区别 - 如果有第二个位置参数,它将作为kwarg参数传递(任何后续的位置参数都以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'12转到argkwargargs[0]但是kwarg 另一个值意外地出现了。


如果您希望考虑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中,您可以使用仅限关键字的参数 ,即以下是替代方法:

def print_stuff(arg, *args, kwarg=None):
    ...

想到它的一个简单方法是:

当一个参数传递给一个函数时,它会被添加到各种位置参数“队列”中。 在分配给此队列时,Python将忽略关键字参数并确定非关键字参数的优先级。 所有关键字参数都在函数调用中最后分配。 你可以想象这是因为Python渴望首先填补位置,因此Python会“改变你的论点”。 所以通过以下呼叫:

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'}}

希望这对你有所帮助

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM