Keyword-only function arguments

Share
Copied to clipboard.
Series: Functions
Trey Hunner smiling in a t-shirt against a yellow wall
Trey Hunner
4 min. read Watch as video Python 3.8—3.12

Let's define a function that accepts a keyword-only argument.

Accepting arbitrary positional arguments

This greet function accepts any number of positional arguments:

>>> def greet(*names):
...     for name in names:
...         print("Hello", name)
...

If we give it some names, it's going to print out Hello, and then the name, for each of those names:

>>> greet("Trey", "Jo", "Ian")
Hello Trey
Hello Jo
Hello Ian

It does this through the * operator, which is capturing all the positional arguments given to this function.

Accepting a keyword-only argument

If we wanted to allow the greeting (Hello) to be customized we could accept a greeting argument:

>>> def greet(*names, greeting):
...     for name in names:
...         print(greeting, name)
...

We might try to call this new greet function like this:

>>> greet("Trey", "Hi")
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: greet() missing 1 required keyword-only argument: 'greeting'

But that gives us an error. The error says that greet is missing one required keyword-only argument greeting.

That error is saying is that greeting is a required argument because it doesn't have a default value and it must be specified as a keyword argument when we call this function.

So if we want to customize greeting, we can pass it in as a keyword argument:

>>> greet("Trey", greeting="Hi")
Hi Trey
>>> greet("Trey", greeting="Hello")
Hello Trey

We probably want greeting to actually have a default value of Hello. We can do that by specifying a default value for the greeting argument:

>>> def greet(*names, greeting="Hello"):
...     for name in names:
...         print(greeting, name)
...
>>> greet("Trey", "Jo")
Hello Trey
Hello Jo

Because greeting is after that *names in our function definition, Python sees greeting as a keyword-only argument: an argument that can only be provided as a keyword argument when this function is called.

It can only be given by its name like this:

>>> greet("Trey", "Jo", greeting="Hi")
Hi Trey
Hi Jo

The print function works this way

This is actually something you'll see in some of Python's built-in functions. For example, the print function accepts any number of positional arguments, as well as four optional keyword-only arguments: sep, end, file, and flush:

>>> help(print)
Help on built-in function print in module builtins:

print(...)
    print(value, ..., sep=' ', end='\n', file=sys.stdout, flush=False)

Note that the documentation for print doesn't use the * syntax, but that ... is print's way of indicating that it accepts any number of values and then all of the arguments after that must be keyword arguments.

If we look at the documentation for greet, you'll see how keyword-only arguments usually show up in documentation:

>>> help(greet)
Help on function greet in module __main__:

greet(*names, greeting='Hello')

Everything after that * (greeting in this case), can only be specified as a keyword argument.

Keyword-only arguments without capturing all positional arguments

It is also possible to make a function that doesn't capture any number of positional arguments, but does have some keyword-only arguments. The syntax for this is really weird.

Let's make a multiply function that accepts x and y arguments:

>>> def multiply(*, x, y):
...     return x * y
...

That lone * before x and y means that they must be specified as keyword arguments.

So, if we were to try to call multiply with two positional arguments, we'll get an error:

>>> multiply(1, 2)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: multiply() takes 0 positional arguments but 2 were given

To call this function, we have to specify x and y as keyword arguments:

>>> multiply(x=1, y=2)
2

If we call this function with nothing you'll see an error message similar to what we saw before about required keyword-only arguments:

>>> multiply()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: multiply() missing 2 required keyword-only arguments: 'x' and 'y'

Keyword-only arguments in the standard library

You'll actually sometimes see this * thing on its own within the Python standard library. For example in the chown function in the os module (used for changing the ownership of a file) uses a lone * to specify keyword-only arguments:

chown(path, uid, gid, *, dir_fd=None, follow_symlinks=True)
    Change the owner and group id of path to the numeric uid and gid.

The chown function documentation shows path, uid, gid, and then a * (which isn't an argument itself), and then dir_fd and follow_symlinks. That lone * is a way of noting that everything after that point is a keyword-only argument.

The last two arguments, dir_fd and follow_symlinks can only be specified by their name when the chown function is called.

Keyword-only arguments come after * in a function definition

So, whenever you see a function that uses * to capture any number of positional arguments (e.g. *args in the function definition), note that any arguments defined after that * capturing can only be specified as a keyword argument (they're keyword-only arguments).

Also if you see a function that has an * on its own with a comma after it, that means that every argument after that point is a keyword-only argument (it must be specified by its name when that function is called).

Series: Functions

Python, like many programming languages, has functions. A function is a block of code you can call to run that code.

Python's functions have a lot of "wait I didn't know that" features. Functions can define default argument values, functions can be called with keyword arguments, and functions can be written to accept any number of arguments.

To track your progress on this Python Morsels topic trail, sign in or sign up.

0%
A Python Tip Every Week

Need to fill-in gaps in your Python skills? I send weekly emails designed to do just that.