简体   繁体   English

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

[英]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的默认值kwargprint_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'12转到argkwargargs[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.

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