Sign in to your Python Morsels account to save your screencast settings.
Don't have an account yet? Sign up here.
Let's make a function that accepts arbitrary keyword arguments.
We're going to make a function called say_things
that we can call with Trey
, ducks=2
, cup=1
in order to print out, Trey has... 2 ducks, 1 cup, That's all!
. It should work like this:
>>> say_things("Trey", ducks=2)
Trey has...
2 ducks
That's all!
We'll start with a function that accepts a name
argument only:
>>> def say_things(name):
... print(f"{name} has...")
... print("That's all!")
...
We can't call this function with the keyword arguments ducks=2
and cup=1
because we will get an error:
>>> say_things("Trey", ducks=2, cup=1)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: say_things() got an unexpected keyword argument 'ducks'
In order to accept any keyword arguments given to this function, we need to use the **
operator.
In our function definition we'll put **
and a variable name (things
in our case) to tell Python that this function should accept any keyword argument given to it and it should store them in a dictionary which that variable name (things
) will point to:
>>> def say_things(name, **things):
... print(f"{name} has...")
... print("That's all!")
...
When our say_things
function is called, the keys in the things
dictionary will be the keyword argument names given (ducks
and cup
in the aspirational example above) and the values will be the values that were given to those arguments (2
and 1
).
To loop over this dictionary, we'll use the items
method to get tuples of key-value pairs:
>>> def say_things(name, **things):
... print(f"{name} has...")
... for name, count in things.items():
... print(f" {count} {name}")
... print("That's all!")
...
So this new function should accept our name
argument and any keyword arguments given to it. For example passing ducks=2
print out 2 ducks
:
>>> say_things("Trey", ducks=2)
Trey has...
2 ducks
That's all!
If we say cup=1
and ideas=3
we'll see those printed out too:
>>> say_things("Trey", ducks=2, cup=1, ideas=3)
Trey has...
2 ducks
1 cup
3 ideas
That's all!
This all works because of **
, which is capturing any keyword arguments given to this function into a dictionary.
You don't really see **
used that often.
This operator is most often used with class inheritance in Python, where you're capturing any arguments given to your class and passing them up to some parent class.
However, there is one method on one of the built-in types in Python that uses **
: the string format
method.
>>> "{n} {item}".format(n=3, item="ducks")
3 ducks
The format
method doesn't just accept n
and item
arguments, it accepts any keyword arguments we can think of to give it.
We can see that by looking at the documentation for the format
method:
>>> help(str.format)
Help on method_descriptor:
format(...)
S.format(*args, **kwargs) -> str
You can see that the string format
method accepts *args
and **kwargs
.
It's capturing all positional arguments and all keyword arguments given to it.
So the format
method can accept any arguments you give to it.
**
to accept arbitrary keyword argumentsIf you need to write a function that accepts arbitrary keyword arguments, you can use the **
operator in your function definition.
Need to fill-in gaps in your Python skills?
Sign up for my Python newsletter where I share one of my favorite Python tips every week.
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.
Need to fill-in gaps in your Python skills? I send weekly emails designed to do just that.