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

与使用参数、关键字参数、*args、**kwargs的Python函数混淆,python,args,keyword-argument,Python,Args,Keyword Argument,给定下面的函数和对print_stuff()的调用,有人能解释一下为什么在没有关键字arg default的情况下调用函数,但将列表传递给*args时会出现意外行为吗 我知道“gotcha”涉及可变/不可变的关键字默认值,但我不认为这与此相关 有人能解释一下为什么会发生这种情况,或者任何语法/调用错误吗 def print_stuff(arg, kwarg=None, *args): print "arg: %s" % arg if kwarg: print "

给定下面的函数和对
print_stuff()
的调用,有人能解释一下为什么在没有关键字arg default的情况下调用函数,但将列表传递给
*args
时会出现意外行为吗

我知道“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
的默认值外,
打印内容(arg,kwarg=None,*args)
打印内容(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'
1
2
转到
arg
kwarg
args[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在参数的顺序上“变换”,因为它急于首先填充位置。所以,打这样的电话:

print_stuff('hi',kwarg='some_kwarg',*范围(1,3))

Python基本上将其转换为:

print\u stuff('hi',1,2,kwarg='some\u kwarg')

然后会因为你给kwarg分配了两次任务而生气

***请注意,这并不一定是实际发生的情况,但这是一种很好的思考方式,因为您将能够处理错误,并且还可以解释为什么在以下通话中:

print_stuff('hi',*范围(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(*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'}}

希望这对您有所帮助

您没有任何只包含关键字的参数,因此,无论您在第二个参数中传递什么,都将被分配给
kwarg
。第二个值作为第二个参数传递有什么意外?谢谢,之所以选择此参数,是因为它提供了一个解释+解决方案。谢谢,将其视为在参数队列中移动是很有用的。