I keep coming across this and my Google Fu (actually DuckDuckGo Judo) cannot find the answer; what is the significance of a single, lone asterisk in the local parameter list of a functions documentation?
os.mkdir(path, mode=0o777, *, dir_fd=None)
…to be clear I’m not asking about *args or **kwargs, but simply ‘*’.
This is a marker that all later arguments must be passed by keyword. To expand your example:
>>> os.open('existing_dir', os.O_DIRECTORY)
>>> os.mkdir('some_dir', 0o644, 3)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: mkdir() takes at most 2 positional arguments (3 given)
>>> os.mkdir('some_dir', 0o644, dir_fd=3)
Similarly, you may run into a lone / in some signatures. This notes that all previous arguments must be passed positionally, not by keyword. This one is much newer and rarer; I don’t have a great example ready for you off the top of my head
Consider the following function signature: func(foo, bar='spam', *args, baz='eggs', **kwargs). That should help you to understand the case of the lone asterisk. If you take away the parameter name args, leaving func(foo, bar='spam', *, baz='eggs', **kwargs), then there’s nothing into which the * operator can pack additional positional arguments. A call with more than the given positional arguments will thus raise a TypeError, which is intentionally supported by the compiler. OTOH, any number of keyword arguments can be passed.
Thanks to @zware and @eryksun, so from your replies I understand that an asterisk in a function signature precedes the name of a local variable into which a tuple containing any additional positional arguments will be placed - effectively allowing an arbitrary number of positional arguments to be passed into the function.
However, if the asterisk is not followed by a variable name and appears on it’s own, this explicitly states that there is nothing into which any extra positional arguments can be packed and thus the implication is that all subsequent arguments must be keyword arguments.
That sounds right to me. Also, as Zachary mentioned, there’s also newer support for indicating position-only arguments via /. For example, for the signature func(foo, bar, /, baz='spam', *, qux='eggs', **kwargs), the parameters foo and bar cannot be passed as keyword arguments.
Practically they all seem the same to me, however only the first one is valid. Why though? I can’t think of why it would matter to the function itself whether it was passed an argument as 'foo' or a='foo' , because inside the function the string 'foo' just gets stored in the variable a.
To be clear, I understand why one can’t place default parameters before non-default parameters in the function definition, as there is a practical reason for that.
I think I understand why all the arguments that follow *args must be keyword arguments (because if **kwargs is included in the function definition, any surplus positional arguments after *args would not have a parameter name associated with them and consequently there would be no key associated with them in the dictionary stored in kwargs.)
Without /, the only way to do the above is something like
def do_something_with(self, some_arg):
def method(_hope_this_does_not_conflict, **kwargs):
def do_something_with(self, some_arg):
def method(*args, **kwargs):
if len(args) != 1:
raise TypeError('something about wrong args')
This is obviously very much a contrived example and doesn’t actually make a whole lot of sense as something you would actually do, but I hope it at least illustrates the idea
For some history, / was originally introduced to be able to represent the signatures of some functions implemented in C which take positional-only arguments. It was later recognized to be a useful-enough addition to make it legal Python syntax.
The python documentation has an index. The first entry is for Symbols, such as ‘*’. Under *, there are 11 entries, the first being function definition, which leads here. Learning to use this and the rest of the index should help you greatly.