We may encounter Python function definitions that look something like this:
def a_function(*args, **kwargs):
...
The asterisks denote parameters able to receive variable-length arguments. (The args
and kwargs
names don't matter โ they're merely conventions, and stand for 'arguments' and 'keyword arguments' respectively. Any appropriate parameter names may be used.)
Say we need a function enabling users to share their hobbies, but we don't know in advance how many hobbies a given user will have:
def my_hobbies(*hobbies):
print("My hobbies: " + ", ".join(hobbies))
Our function now accepts one or more arguments:
>>> my_hobbies('reading', 'writing')
My hobbies: reading, writing
>>> my_hobbies('reading', 'writing', 'hiking', 'learning Python')
My hobbies: reading, writing, hiking, learning Python
Conveniently, we can also call our function by passing it a tuple, using similar asterisk syntax:
>>> some_hobbies = ('reading', 'writing', 'hiking', 'learning Python')
>>> my_hobbies(*some_hobbies)
My hobbies: reading, writing, hiking, learning Python
Now say we want a function enabling users to share their favorite things in various categories, but we don't know in advance how many categories a given user will select:
def my_faves(**favorites):
print("My favorite things...")
for category, fave in favorites.items():
print(f"{category}: {fave}")
Our function now accepts one or more keyword arguments:
>>> my_faves(Color='green', Fruit='persimmon')
My favorite things...
Color: green
Fruit: persimmon
>>> my_faves(Season='winter', Language='Python', Website='dev.to')
My favorite things...
Season: fall
Language: Python
Website: dev.to
We can also call our function by passing it a dictionary, using similar double asterisk syntax:
>>> some_faves = {"Animal": "whale", "Summer Hobby": "hiking"}
>>> my_faves(**some_faves)
My favorite things...
Animal: whale
Summer Hobby: hiking
A function may be defined with a mixture of formal parameters, variable-length parameters, and variable-length keyword parameters. When doing so, they must appear in the definition in the following order:
def a_function(arg, *args, **kwargs):
...
More information can be found in the Python documentation.
Was this helpful? Did I save you some time?
Top comments (7)
*args
and**kwargs
are so powerful. I have cut large sections of hard to maintain code completely out with them. I do find it hard to teach/learn/grasp. I just released a post trying to share them as well.I think some of this comes from seeing really confusing implementations. I really like how you chose to use
*hobbies
and**favorites
here. I think generalizing with*args
and**kwargs
only adds to the confusion, and for some reason that is what appears more often than not.A nice simple concise explanation of args and kwargs
Thanks! ๐
What is the difference if I just used list or dictionary as arguments?
def my_hobbies(hobbies_list):
print("My hobbies: " + ", ".join(hobbies_list))
In our simple example, there isn't much of a difference.
In a real-world example, the
*args
and*kwargs
syntax give us more options in how we accept data into our function.The decision is largely one between:
A) forcing the use of structured data, and...
B) not needing to know the structure in advance.
In your example, we must always pass in a list or dictionary, even if we are only passing in a single hobby. (This approach is not necessarily bad -- it may, in fact, be the right solution.) If, instead, we allow variable-length arguments -- by using the
*args
or*kwargs
syntax -- then we do not need to structure the data in advance.A more in-depth discussion related to your question can be found here.
Excellent explanation, thanks!
You're welcome! ๐