理解' *' "仅限关键字" python3函数中的参数表示法

时间:2015-10-15 01:44:48

标签: python python-3.x keyword-argument

keyword only arguments一起使用时,我在python3中遇到partial功能的一些困难行为。关键字唯一参数的其他info

这是我的代码:

def awesome_function(a = 0, b = 0, *, prefix):
    print('a ->', a)
    print('b ->', b)
    print('prefix ->', prefix)
    return prefix + str(a+b)

以下是我对部分的理解:

>>> two_pow = partial(pow, 2)
>>> two_pow(5)
32
>>>

我在上面的示例中理解,partial使pow函数的第二个参数成为two_pow的唯一参数。

我的问题是为什么以下工作:

>>> g = partial(awesome_function, prefix='$')
>>> g(3, 5)
a -> 3
b -> 5
prefix -> $
'$8'
>>>

但是我得到了错误:

>>> awesome_function(prefix='$', 3, 5)
  File "<stdin>", line 1
SyntaxError: non-keyword arg after keyword arg
>>>

我知道我可以通过

直接致电awesome_function
>>> awesome_function(prefix='$', a = 3, b = 5)
a -> 3
b -> 5
prefix -> $
'$8'
>>>

2 个答案:

答案 0 :(得分:4)

根据function calls in Python的语义,要传递的参数的规则如下

argument_list   ::=  positional_arguments ["," keyword_arguments]
                       ["," "*" expression] ["," keyword_arguments]
                       ["," "**" expression]
                     | keyword_arguments ["," "*" expression]
                       ["," keyword_arguments] ["," "**"     expression]
                     | "*" expression ["," keyword_arguments] ["," "**" expression]
                     | "**" expression

如您所见,位置参数应始终出现在函数调用的开头。它们不能出现在任何其他地方。当你这样做

awesome_function(prefix='$', 3, 5)

它违反了上述规则,因为您在关键字参数(3)之后传递了两个位置参数(5prefix)。这就是为什么你得到一个SyntaxError,因为Python无法解析函数调用表达式。

但是,当你使用partial时,它可以工作,因为partial创建了一个新的函数对象,它存储了要传递给它的所有参数。当您实际调用partial返回的函数对象时,它首先应用所有位置参数,然后应用关键字参数。

答案 1 :(得分:1)

您得到的错误 - SyntaxError: non-keyword arg after keyword arg - 是因为您尝试在关键字参数之后发送位置参数(如3,5),这不是有效的语法,因此会出现语法错误。在函数调用中 -

 awesome_function(prefix='$', 3, 5)
                          ^   ^  ^
                          |     These two are the positional argument.
                          ----- This is the keyword argument.                                

使用functools.partial时有效,因为functools.partial知道将位置参数放在关键字参数之前,因此当您使用位置参数调用部分函数 - g()时,它会发送这些位置参数在关键字参数之前。因此,在您的情况下g(3, 5) ==> awesome_function(3, 5, prefix='$')

一个简单的例子来展示这个 -

>>> from functools import partial
>>> def func(a=0,b=1):
...     print(a,b)
...
>>> ptfunc = partial(func,a=10)
>>> ptfunc(20)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: func() got multiple values for argument 'a'

在上面的例子中,当我们调用ptfunc(20)时,20首先作为位置参数传递,然后传递关键字参数a=10,因此它抱怨它有多个值参数a

同样在the documentation -

中给出
  

functools.partial大致相当于:

def partial(func, *args, **keywords):
    def newfunc(*fargs, **fkeywords):
        newkeywords = keywords.copy()
        newkeywords.update(fkeywords)
        return func(*(args + fargs), **newkeywords)
    newfunc.func = func
    newfunc.args = args
    newfunc.keywords = keywords
    return newfunc