DEV Community

Adam Lombard
Adam Lombard

Posted on • Edited on

Python: What are *args and **kwargs?

We may encounter Python function definitions that look something like this:

def a_function(*args, **kwargs):
    ...
Enter fullscreen mode Exit fullscreen mode

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))
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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}")
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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):
    ...
Enter fullscreen mode Exit fullscreen mode

More information can be found in the Python documentation.


Was this helpful? Did I save you some time?

🫖 Buy Me A Tea! ☕️


Top comments (7)

Collapse
 
waylonwalker profile image
Waylon Walker • Edited

*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.

understanding python args and kwargs

Collapse
 
machanic16 profile image
Joel Tovar

Excellent explanation, thanks!

Collapse
 
adamlombard profile image
Adam Lombard

You're welcome! 🙂

Collapse
 
hasii2011 profile image
Humberto A Sanchez II

A nice simple concise explanation of args and kwargs

Collapse
 
adamlombard profile image
Adam Lombard

Thanks! 🙂

Collapse
 
serg_syd profile image
Sergio • Edited

What is the difference if I just used list or dictionary as arguments?

def my_hobbies(hobbies_list):
print("My hobbies: " + ", ".join(hobbies_list))

Collapse
 
adamlombard profile image
Adam Lombard • Edited

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.