Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

understanding '*' "keyword only" argument notation in python3 functions [duplicate]

I am having some difficulty behaviour of keyword only arguments feature in python3 when used with partial. Other info on keyword only arguments.

Here is my code:

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

Here is my understanding of partial:

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

What I understood is in the above example, partial makes the second argument to pow function as the only argument of two_pow.

My question is why does the following work:

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

But I get error in this:

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

I know that I can call awesome_function directly by

>>> awesome_function(prefix='$', a = 3, b = 5)
a -> 3
b -> 5
prefix -> $
'$8'
>>>
like image 573
kmad1729 Avatar asked Oct 15 '15 01:10

kmad1729


1 Answers

As per the semantics of the function calls in Python, the rules for the arguments to be passed are as follows

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

As you see here, the positional arguments should always appear at the beginning of the function calls. They cannot appear anywhere else. When you do

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

it violates the above rule, as you are passing two positional arguments (3 and 5) after a keyword argument (prefix). That is why you are getting a SyntaxError, as Python is not able to parse the function call expression.


But, when you are using partial it works, because partial creates a new function object and it stores all the parameters to be passed to it. When you actually invoke the function object returned by partial, it applies all the positional arguments first and then the keyword arguments.

like image 86
thefourtheye Avatar answered Oct 09 '22 06:10

thefourtheye