I was going trough some code, and I came across the following function:
def foo(self, arg1=1, *, arg2=2):
pass
I was surprised to see keyword arguments on the left side of the *, the positional arguments. I notice then that I can call foo in both of the following ways:
>>> foo(1)
>>> foo(arg1=1)
I think I would be expecting the second call to fail as I am calling foo using a named argument by providing the keyword arg1.
With that said, am I using positional arguments in both scenarios, or is the second call to foo a named argument?
The best sentence that I found that best describes this is:
"The trick here is to realize that a “keyword argument” is a concept of the call site, not the declaration. But a “keyword only argument” is a concept of the declaration, not the call site."
Below is a concise explanation copied from here in case the link dies at some point.
def bar(a, # <- this parameter is a normal python parameter
b=1, # <- this is a parameter with a default value
*, # <- all parameters after this are keyword only
c=2, # <- keyword only argument with default value
d): # <- keyword only argument without default value
pass
The arg1 argument is allowed to be called as either a positional argument, or a keyword argument.
As of Python 3.8, it is possible to specify some arguments as positional only. See PEP 570. Prior to 3.8, this isn't possible unless you write a python C extension.
The 3.8 syntax looks like this (directly from the PEP):
def name(positional_only_parameters, /, positional_or_keyword_parameters,
*, keyword_only_parameters): ...
...prior to 3.8, the only legal syntax is this:
def name(positional_or_keyword_parameters, *, keyword_only_parameters): ...
Despite the similarity in syntax, there is no relationship between keyword arguments and parameters with default values.
key=value is used both to assign a default value to a parameter when the function is defined, and to pass an argument for a parameter when the function is called.
A parameter without a default value can be assigned using a keyword argument:
def foo(a):
return a + 3
assert foo(a=5) == 8
A parameter with a default value can be assigned without a keyword argument:
def foo(a=5):
return a + 3
assert foo() == 8
assert foo(1) == 4
Is a complex answer by using the * like the argument ( the Python version, define and use it ).
In your case:
>>> foo(1,2,)
>>> foo(1,2)
Note that:
Try to use this and see the difference ( without self ):
>>> def foo( arg1=1, *, arg2=2):
... pass
...
>>> foo(arg1=1,arg2=2)
>>> def foo( arg1=1, *, arg2=2):
... pass
...
>>> foo(arg1=1,arg2=2)
>>> foo(arg1=1)
>>> foo(arg1=1,)
>>> foo(arg2=2)
>>> foo(arg2=2,1)
File "<stdin>", line 1
SyntaxError: positional argument follows keyword argument
>>> foo(2,1)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: foo() takes from 0 to 1 positional arguments but 2 were given
>>> foo(arg1=1,2)
File "<stdin>", line 1
SyntaxError: positional argument follows keyword argument
One star * defines positional arguments (you can receive any number of arguments and treat the passed arguments as a tuple);
Two stars ** define keywords arguments.
A good example comes from this tutorial (the keyword-only arguments without positional arguments part):
def with_previous(iterable, *, fillvalue=None):
"""Yield each iterable item along with the item before it."""
previous = fillvalue
for item in iterable:
yield previous, item
previous = item
>>> list(with_previous([2, 1, 3], fillvalue=0))
[(0, 2), (2, 1), (1, 3)]
That its value could be sent as positional arguments.
See this tutorial for more info about arguments.
Python 3.x introduces more intuitive keyword-only arguments with PEP-3102 (you can specify * in the argument list).
One good alternative answer is this:
Related
What does a bare asterisk in the parameters of a function do?
When I looked at the pickle module, I see this:
pickle.dump(obj, file, protocol=None, *, fix_imports=True)
I know about a single and double asterisks preceding parameters (for variable number of parameters), but this precedes nothing. And I'm pretty sure this has nothing to do with pickle. That's probably just an example of this happening. I only learned its name when I sent this to the interpreter:
>>> def func(*):
... pass
...
File "<stdin>", line 1
SyntaxError: named arguments must follow bare *
If it matters, I'm on python 3.3.0.
Bare * is used to force the caller to use named arguments - so you cannot define a function with * as an argument when you have no following keyword arguments.
See this answer or Python 3 documentation for more details.
While the original answer answers the question completely, just adding a bit of related information. The behaviour for the single asterisk derives from PEP-3102. Quoting the related section:
The second syntactical change is to allow the argument name to
be omitted for a varargs argument. The meaning of this is to
allow for keyword-only arguments for functions that would not
otherwise take a varargs argument:
def compare(a, b, *, key=None):
...
In simple english, it means that to pass the value for key, you will need to explicitly pass it as key="value".
def func(*, a, b):
print(a)
print(b)
func("gg") # TypeError: func() takes 0 positional arguments but 1 was given
func(a="gg") # TypeError: func() missing 1 required keyword-only argument: 'b'
func(a="aa", b="bb", c="cc") # TypeError: func() got an unexpected keyword argument 'c'
func(a="aa", b="bb", "cc") # SyntaxError: positional argument follows keyword argument
func(a="aa", b="bb") # aa, bb
the above example with **kwargs
def func(*, a, b, **kwargs):
print(a)
print(b)
print(kwargs)
func(a="aa",b="bb", c="cc") # aa, bb, {'c': 'cc'}
Semantically, it means the arguments following it are keyword-only, so you will get an error if you try to provide an argument without specifying its name. For example:
>>> def f(a, *, b):
... return a + b
...
>>> f(1, 2)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: f() takes 1 positional argument but 2 were given
>>> f(1, b=2)
3
Pragmatically, it means you have to call the function with a keyword argument. It's usually done when it would be hard to understand the purpose of the argument without the hint given by the argument's name.
Compare e.g. sorted(nums, reverse=True) vs. if you wrote sorted(nums, True). The latter would be much less readable, so the Python developers chose to make you to write it the former way.
Suppose you have function:
def sum(a,key=5):
return a + key
You can call this function in 2 ways:
sum(1,2) or sum(1,key=2)
Suppose you want function sum to be called only using keyword arguments.
You add * to the function parameter list to mark the end of positional arguments.
So function defined as:
def sum(a,*,key=5):
return a + key
may be called only using sum(1,key=2)
I've found the following link to be very helpful explaining *, *args and **kwargs:
https://pythontips.com/2013/08/04/args-and-kwargs-in-python-explained/
Essentially, in addition to the answers above, I've learned from the site above (credit: https://pythontips.com/author/yasoob008/) the following:
With the demonstration function defined first below, there are two examples, one with *args and one with **kwargs
def test_args_kwargs(arg1, arg2, arg3):
print "arg1:", arg1
print "arg2:", arg2
print "arg3:", arg3
# first with *args
>>> args = ("two", 3,5)
>>> test_args_kwargs(*args)
arg1: two
arg2: 3
arg3: 5
# now with **kwargs:
>>> kwargs = {"arg3": 3, "arg2": "two","arg1":5}
>>> test_args_kwargs(**kwargs)
arg1: 5
arg2: two
arg3: 3
So *args allows you to dynamically build a list of arguments that will be taken in the order in which they are fed, whereas **kwargs can enable the passing of NAMED arguments, and can be processed by NAME accordingly (irrespective of the order in which they are fed).
The site continues, noting that the correct ordering of arguments should be:
some_func(fargs,*args,**kwargs)
What does a bare asterisk in the parameters of a function do?
When I looked at the pickle module, I see this:
pickle.dump(obj, file, protocol=None, *, fix_imports=True)
I know about a single and double asterisks preceding parameters (for variable number of parameters), but this precedes nothing. And I'm pretty sure this has nothing to do with pickle. That's probably just an example of this happening. I only learned its name when I sent this to the interpreter:
>>> def func(*):
... pass
...
File "<stdin>", line 1
SyntaxError: named arguments must follow bare *
If it matters, I'm on python 3.3.0.
Bare * is used to force the caller to use named arguments - so you cannot define a function with * as an argument when you have no following keyword arguments.
See this answer or Python 3 documentation for more details.
While the original answer answers the question completely, just adding a bit of related information. The behaviour for the single asterisk derives from PEP-3102. Quoting the related section:
The second syntactical change is to allow the argument name to
be omitted for a varargs argument. The meaning of this is to
allow for keyword-only arguments for functions that would not
otherwise take a varargs argument:
def compare(a, b, *, key=None):
...
In simple english, it means that to pass the value for key, you will need to explicitly pass it as key="value".
def func(*, a, b):
print(a)
print(b)
func("gg") # TypeError: func() takes 0 positional arguments but 1 was given
func(a="gg") # TypeError: func() missing 1 required keyword-only argument: 'b'
func(a="aa", b="bb", c="cc") # TypeError: func() got an unexpected keyword argument 'c'
func(a="aa", b="bb", "cc") # SyntaxError: positional argument follows keyword argument
func(a="aa", b="bb") # aa, bb
the above example with **kwargs
def func(*, a, b, **kwargs):
print(a)
print(b)
print(kwargs)
func(a="aa",b="bb", c="cc") # aa, bb, {'c': 'cc'}
Semantically, it means the arguments following it are keyword-only, so you will get an error if you try to provide an argument without specifying its name. For example:
>>> def f(a, *, b):
... return a + b
...
>>> f(1, 2)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: f() takes 1 positional argument but 2 were given
>>> f(1, b=2)
3
Pragmatically, it means you have to call the function with a keyword argument. It's usually done when it would be hard to understand the purpose of the argument without the hint given by the argument's name.
Compare e.g. sorted(nums, reverse=True) vs. if you wrote sorted(nums, True). The latter would be much less readable, so the Python developers chose to make you to write it the former way.
Suppose you have function:
def sum(a,key=5):
return a + key
You can call this function in 2 ways:
sum(1,2) or sum(1,key=2)
Suppose you want function sum to be called only using keyword arguments.
You add * to the function parameter list to mark the end of positional arguments.
So function defined as:
def sum(a,*,key=5):
return a + key
may be called only using sum(1,key=2)
I've found the following link to be very helpful explaining *, *args and **kwargs:
https://pythontips.com/2013/08/04/args-and-kwargs-in-python-explained/
Essentially, in addition to the answers above, I've learned from the site above (credit: https://pythontips.com/author/yasoob008/) the following:
With the demonstration function defined first below, there are two examples, one with *args and one with **kwargs
def test_args_kwargs(arg1, arg2, arg3):
print "arg1:", arg1
print "arg2:", arg2
print "arg3:", arg3
# first with *args
>>> args = ("two", 3,5)
>>> test_args_kwargs(*args)
arg1: two
arg2: 3
arg3: 5
# now with **kwargs:
>>> kwargs = {"arg3": 3, "arg2": "two","arg1":5}
>>> test_args_kwargs(**kwargs)
arg1: 5
arg2: two
arg3: 3
So *args allows you to dynamically build a list of arguments that will be taken in the order in which they are fed, whereas **kwargs can enable the passing of NAMED arguments, and can be processed by NAME accordingly (irrespective of the order in which they are fed).
The site continues, noting that the correct ordering of arguments should be:
some_func(fargs,*args,**kwargs)
I defined a function like this:
def func(must, op1=1, op2=2, op3=3, *arguments, **keywords):
print(must, op1, op2, op3)
for arg in arguments:
print(arg)
for kw in keywords.keys():
print(kw, ":", keywords[kw])
I called it:
func(1, op1=1, op2=2, op3=3, 1, 3)
Of course, I got an error:
Error information
In my mind, *arguments are positional parameter. And the op1, op2, op2 are keyword parameters. So *arguments should be before op1, op2, op3. Then I changed the definition:
def func(must, *arguments, op1=1, op2=2, op3=3, **keywords):
print(must, op1, op2, op3)
for arg in arguments:
print (arg)
for kw in keywords.keys():
print (kw, ":", keywords[kw])
Why doesn't the Python interpreter think the first definition is a mistake?
Hi All,
I updated this topic.
After discuss with my colleague, I think that:
definition of a function, the parameters are default or non-default parameters
call a function, the parameters are positional or keyword parameters
So, whether the parameter is a positional parameter depends on you call the function, not define the function.
While slightly counterintuitive, the first definition is completely unambiguous:
func(must, op1=1, op2=2, op3=3, *args, **kwargs)
This means that op1, op2, and op3 are optional positional arguments. You can't specify any of *args without explicitly setting all three first. You got the error because you attempted to place positional arguments after keywords. It's irrelevant that the keywords name positional arguments. You can make the same call like this:
func(1, 1, 2, 3, 1, 3)
That will not raise an error. Neither will
func(1, 2)
In that case, only op1 will have a non-default value, *args will be empty, and you can set whatever keywords you want, including op2 and op3.
Aside from *args, all positional arguments are named and can be passed in by keyword as well. In practice, though, all arguments that come after the first one passed in as a keyword must be passed in as a keyword. It therefore follows that you can't pass in *args if you pass in any named positional argument as a keyword.
In your second example, you've made the op arguments keyword-only by placing them after the splat (*). Any positional arguments after the first are therefore absorbed into *args.
Keep in mind that keyword-only arguments don't need defaults. A function like def func(*, a): pass can only be invoked as func(a=3) and never as func(3).
On a side note, the splat argument is conventionally named *args and the splatty splat one **kwargs. I have stuck with that convention throughout my answer.
At the first example, you can call your function like this (it's still working):
func(9, 9, 9, 9)
Python determine which parameter is keyword when you call a function.
Here's more example:
def func(a,b,c=1,d): # -> a, b, c, d are parameters and c has default value = 1
pass
func(1, 2, 3, 4) # -> call with 4 postional parameters
func(1, 3, d=3) # -> call with 2 positional parameters and 1 keyword parameters
What does a bare asterisk in the parameters of a function do?
When I looked at the pickle module, I see this:
pickle.dump(obj, file, protocol=None, *, fix_imports=True)
I know about a single and double asterisks preceding parameters (for variable number of parameters), but this precedes nothing. And I'm pretty sure this has nothing to do with pickle. That's probably just an example of this happening. I only learned its name when I sent this to the interpreter:
>>> def func(*):
... pass
...
File "<stdin>", line 1
SyntaxError: named arguments must follow bare *
If it matters, I'm on python 3.3.0.
Bare * is used to force the caller to use named arguments - so you cannot define a function with * as an argument when you have no following keyword arguments.
See this answer or Python 3 documentation for more details.
While the original answer answers the question completely, just adding a bit of related information. The behaviour for the single asterisk derives from PEP-3102. Quoting the related section:
The second syntactical change is to allow the argument name to
be omitted for a varargs argument. The meaning of this is to
allow for keyword-only arguments for functions that would not
otherwise take a varargs argument:
def compare(a, b, *, key=None):
...
In simple english, it means that to pass the value for key, you will need to explicitly pass it as key="value".
def func(*, a, b):
print(a)
print(b)
func("gg") # TypeError: func() takes 0 positional arguments but 1 was given
func(a="gg") # TypeError: func() missing 1 required keyword-only argument: 'b'
func(a="aa", b="bb", c="cc") # TypeError: func() got an unexpected keyword argument 'c'
func(a="aa", b="bb", "cc") # SyntaxError: positional argument follows keyword argument
func(a="aa", b="bb") # aa, bb
the above example with **kwargs
def func(*, a, b, **kwargs):
print(a)
print(b)
print(kwargs)
func(a="aa",b="bb", c="cc") # aa, bb, {'c': 'cc'}
Semantically, it means the arguments following it are keyword-only, so you will get an error if you try to provide an argument without specifying its name. For example:
>>> def f(a, *, b):
... return a + b
...
>>> f(1, 2)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: f() takes 1 positional argument but 2 were given
>>> f(1, b=2)
3
Pragmatically, it means you have to call the function with a keyword argument. It's usually done when it would be hard to understand the purpose of the argument without the hint given by the argument's name.
Compare e.g. sorted(nums, reverse=True) vs. if you wrote sorted(nums, True). The latter would be much less readable, so the Python developers chose to make you to write it the former way.
Suppose you have function:
def sum(a,key=5):
return a + key
You can call this function in 2 ways:
sum(1,2) or sum(1,key=2)
Suppose you want function sum to be called only using keyword arguments.
You add * to the function parameter list to mark the end of positional arguments.
So function defined as:
def sum(a,*,key=5):
return a + key
may be called only using sum(1,key=2)
I've found the following link to be very helpful explaining *, *args and **kwargs:
https://pythontips.com/2013/08/04/args-and-kwargs-in-python-explained/
Essentially, in addition to the answers above, I've learned from the site above (credit: https://pythontips.com/author/yasoob008/) the following:
With the demonstration function defined first below, there are two examples, one with *args and one with **kwargs
def test_args_kwargs(arg1, arg2, arg3):
print "arg1:", arg1
print "arg2:", arg2
print "arg3:", arg3
# first with *args
>>> args = ("two", 3,5)
>>> test_args_kwargs(*args)
arg1: two
arg2: 3
arg3: 5
# now with **kwargs:
>>> kwargs = {"arg3": 3, "arg2": "two","arg1":5}
>>> test_args_kwargs(**kwargs)
arg1: 5
arg2: two
arg3: 3
So *args allows you to dynamically build a list of arguments that will be taken in the order in which they are fed, whereas **kwargs can enable the passing of NAMED arguments, and can be processed by NAME accordingly (irrespective of the order in which they are fed).
The site continues, noting that the correct ordering of arguments should be:
some_func(fargs,*args,**kwargs)
What does a bare asterisk in the parameters of a function do?
When I looked at the pickle module, I see this:
pickle.dump(obj, file, protocol=None, *, fix_imports=True)
I know about a single and double asterisks preceding parameters (for variable number of parameters), but this precedes nothing. And I'm pretty sure this has nothing to do with pickle. That's probably just an example of this happening. I only learned its name when I sent this to the interpreter:
>>> def func(*):
... pass
...
File "<stdin>", line 1
SyntaxError: named arguments must follow bare *
If it matters, I'm on python 3.3.0.
Bare * is used to force the caller to use named arguments - so you cannot define a function with * as an argument when you have no following keyword arguments.
See this answer or Python 3 documentation for more details.
While the original answer answers the question completely, just adding a bit of related information. The behaviour for the single asterisk derives from PEP-3102. Quoting the related section:
The second syntactical change is to allow the argument name to
be omitted for a varargs argument. The meaning of this is to
allow for keyword-only arguments for functions that would not
otherwise take a varargs argument:
def compare(a, b, *, key=None):
...
In simple english, it means that to pass the value for key, you will need to explicitly pass it as key="value".
def func(*, a, b):
print(a)
print(b)
func("gg") # TypeError: func() takes 0 positional arguments but 1 was given
func(a="gg") # TypeError: func() missing 1 required keyword-only argument: 'b'
func(a="aa", b="bb", c="cc") # TypeError: func() got an unexpected keyword argument 'c'
func(a="aa", b="bb", "cc") # SyntaxError: positional argument follows keyword argument
func(a="aa", b="bb") # aa, bb
the above example with **kwargs
def func(*, a, b, **kwargs):
print(a)
print(b)
print(kwargs)
func(a="aa",b="bb", c="cc") # aa, bb, {'c': 'cc'}
Semantically, it means the arguments following it are keyword-only, so you will get an error if you try to provide an argument without specifying its name. For example:
>>> def f(a, *, b):
... return a + b
...
>>> f(1, 2)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: f() takes 1 positional argument but 2 were given
>>> f(1, b=2)
3
Pragmatically, it means you have to call the function with a keyword argument. It's usually done when it would be hard to understand the purpose of the argument without the hint given by the argument's name.
Compare e.g. sorted(nums, reverse=True) vs. if you wrote sorted(nums, True). The latter would be much less readable, so the Python developers chose to make you to write it the former way.
Suppose you have function:
def sum(a,key=5):
return a + key
You can call this function in 2 ways:
sum(1,2) or sum(1,key=2)
Suppose you want function sum to be called only using keyword arguments.
You add * to the function parameter list to mark the end of positional arguments.
So function defined as:
def sum(a,*,key=5):
return a + key
may be called only using sum(1,key=2)
I've found the following link to be very helpful explaining *, *args and **kwargs:
https://pythontips.com/2013/08/04/args-and-kwargs-in-python-explained/
Essentially, in addition to the answers above, I've learned from the site above (credit: https://pythontips.com/author/yasoob008/) the following:
With the demonstration function defined first below, there are two examples, one with *args and one with **kwargs
def test_args_kwargs(arg1, arg2, arg3):
print "arg1:", arg1
print "arg2:", arg2
print "arg3:", arg3
# first with *args
>>> args = ("two", 3,5)
>>> test_args_kwargs(*args)
arg1: two
arg2: 3
arg3: 5
# now with **kwargs:
>>> kwargs = {"arg3": 3, "arg2": "two","arg1":5}
>>> test_args_kwargs(**kwargs)
arg1: 5
arg2: two
arg3: 3
So *args allows you to dynamically build a list of arguments that will be taken in the order in which they are fed, whereas **kwargs can enable the passing of NAMED arguments, and can be processed by NAME accordingly (irrespective of the order in which they are fed).
The site continues, noting that the correct ordering of arguments should be:
some_func(fargs,*args,**kwargs)