What is the significance of a single, lone asterisk in a functions documentation?

Hello all,

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?

For example…

os.mkdir(path, mode=0o777, *, dir_fd=None)

…to be clear I’m not asking about *args or **kwargs, but simply ‘*’.

Thanks in advance!

This is a marker that all later arguments must be passed by keyword. To expand your example:

>>> os.open('existing_dir', os.O_DIRECTORY)
3
>>> os.listdir(3)
[]
>>> 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)
>>> os.listdir(3)
['some_dir']

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 :slight_smile:

3 Likes

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.

2 Likes

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.

I hope that I’ve got that right.

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.

2 Likes