Reputation: 1123
why using this line of code in python gives error:
required, *args, **kwargs = "Welcome to...", 1, 2, 3, site='stackoverflow.com'
^
SyntaxError: invalid syntax
while using it in function signatures is ok like:
def function1(required, *args, **kwargs):
pass
function1("Welcome to...", 1, 2, 3, site='stackoverflow.com')
Upvotes: 3
Views: 2129
Reputation: 1244
required, *args, **kwargs = "Welcome to...", 1, 2, 3, site='stackoverflow.com'
^
Star notation like this generally goes last in an expansion, especially functional invocation or function argument specification. Additionally, you can not assign to it in this way.
[*prefix, 2, 3, 4, *mid, 5, *suffix]
Literal forms of certain complex object types (such as list, above, and dictionary) permit expansion using star notation at any point in the expression, and to a degree function invocations do, too. In argument specification where you are declaring the desire for "unlimited information", these notations have additional meaning and consequence.
def foo(bar, *baz, diz): ...
diz
is now name-only and can not be passed in positionally. Without a default value, it is now a required named argument. Because being able to declare arguments as keyword-only is actually quite useful, and accepting and stuffing additional positional arguments into an unused variable a bit of an anti-pattern, PEP 3102 — Keyword-Only Arguments was written up and accepted to formalize using just a *
, bare, to specify "everything after this point is keyword only". Additionally, there is a /
marker to denote the separation between positional-only, and positional-or-keyword: the reverse. Reference.
Boils down to: literal expansion notation and argument specification notation mean and do different things.
Upvotes: 3
Reputation: 16536
My guess is because if we want this **kwargs
to work, we have to have keyword-argument on the right hand side(It should be converted to dictionary) just like you did :
required, *args, **kwargs = "Welcome to...", 1, 2, 3, site='stackoverflow.com'
But as we know right hand side of an assignment is evaluated fist(then the unpacking occurs). so in this case you can think of an another assignment in an expression which is invalid. for example :
a = (1, 2, 3) # Valid
b = (1, 2, var=20) # Invalid
By looking at:
from dis import dis
dis('a, b, c = 5, 4, 3')
1 0 LOAD_CONST 0 ((5, 4, 3))
2 UNPACK_SEQUENCE 3
4 STORE_NAME 0 (a)
6 STORE_NAME 1 (b)
8 STORE_NAME 2 (c)
10 LOAD_CONST 1 (None)
12 RETURN_VALUE
Python tries to build a tuple from right hand side of the assignment, you can't have an assignment statement in there. I think same thing is happened and that's the reason.
Upvotes: 3
Reputation: 724
Python doesn't allow destructuring the same way as JavaScript does (I assume you have a background in it). The function signature is special, it allows a variadic number of parameters - without the syntax you would need to specify all the parameters and set them by default to None. The *args
(for positional arguments) and **kargs
(for keyword arguments) allows to work with all the parameters as the list (or dictionary in case of keyword arguments).
Python can destruct only tuples, so only the following code is valid.
first_param, second_param, third_param = "Welcome to...", 1, 2
You can even use one asterisk to substitute multiple values, but it can be there only once
first_param, *rest, last_param = "Welcome to...", 1, 2, 3
Also, you need to destruct the whole tuple, so the following code is not valid and will fail at runtime.
first_param, second_param = "Welcome to...", 1, 2
The site='stackoverflow.com'
is possible only as keyword argument.
def function1(param1=1, param2=2):
pass
function1(param2='hello')
This is the only case where you can use this syntax.
Upvotes: 3