kwargs vs args: What do *args and **kwargs mean in Python?

Learn what are `*args` and `**kwargs` with examples and different ways to use them in code.

Picture of Nsikak Imoh, author of Macsika Blog
Blank image with the text kwargs vs args: What do *args and **kwargs mean in Python?
Blank image with the text kwargs vs args: What do *args and **kwargs mean in Python?

Table of Content

The *args and **kwargs are common placeholders for parameters in functions to allow an arbitrary number of positional arguments and keyword arguments, respectively.

In this article, you will see in detail what are *args and **kwargs with examples and different ways to use them in code.

Special Symbols Used for Passing Arbitrary Number of Arguments in Python

In Python, we can pass an arbitrary number of arguments to a function using special symbols. There are two special symbols used for this:

  • *args: for Positional (Non-Keyword) Arguments
  • **kwargs: for Keyword Arguments

What does the *args mean in Python and how to use it?

The *args allows for any number of optional positional arguments (parameters), which will be assigned to a tuple named args.

This means that *args will give you all positional arguments sent to the function parameters as a tuple, which allows you to perform all actions that can be performed on tuples such as indexing, iterating, etc.

def foo(*args):
    for a in args:
        print(a)        

foo(1)
# 1

foo(1,2,3)
# 1
# 2
# 3

Highlighted code sample.

What does the **kwargs mean in Python and how to use it?

The **kwargs allows for any number of optional keyword arguments (parameters), which will be in a dict named kwargs.

This means that **kwargs will give you all keyword arguments sent to the function parameters, except for the parameters corresponding to a formal parameter, as a dictionary.

def bar(**kwargs):
    for a in kwargs:
        print(a, kwargs[a])  

bar(name='one', age=27)
# name one
# age 27

Highlighted code sample.

Combining *args, **kwargs, and other arguments

You can mix *args, **kwargs with normal arguments to allow a set of fixed and some variable arguments in a function:

Variation 1:

def foo(*args, **kwargs):
   pass
Highlighted code sample.

Variation 2:

def foo(kind, *args, **kwargs):
   pass
Highlighted code sample.

Variation 3:

def foo(kind=None, *args, **kwargs):
   pass
Highlighted code sample.

It is possible to pass arguments from a list when calling a function by unpacking the list.

def foo(bar, lee):
    print(bar, lee)

l = [1,2]

foo(*l)
# 1 2

Highlighted code sample.

It is also possible to use this the other way around, using a dictionary:

def foo(a, b, c):
    print(a, b, c)

obj = {'b':10, 'c':'lee'}

foo(100,**obj)
# 100 10 lee

Highlighted code sample.

Note

When you pass a Python dict as a keyword argument passing, they are usually ordered.

However, from Python 3.6, keyword arguments are guaranteed to be ordered.

This means that the order of elements in **kwargs now corresponds to the order in which keyword arguments were passed to the function.

From Python 3.7 upward, it's a standard to do the above.

From python 3.8 onward, you can use / in function definition to enforce positional only parameters.

In the following example, parameters a and b are positional-only, while c or d can be positional or keyword, and e or f are required to be keywords:

def f(a, b, /, c, d, *, e, f):
    pass
Highlighted code sample.

One reason to use / is that it allows you to change the names of the parameters in the function and not have to update at any place where the function is called (you can be sure that no caller of the function has used the names of the parameters to supply arguments since it isn't used).

TLDR Summary

  • To accept any number of positional arguments using *args: def foo(*args): pass, here foo accepts any number of positional arguments, i.e., the following calls are valid foo(1), foo(1, 'bar')
  • To accept any number of keyword arguments using **kwargs: def foo(**kwargs): pass, here 'foo' accepts any number of keyword arguments, i.e., the following calls are valid foo(name='Tom'), foo(name='Tom', age=33)
  • To accept any number of positional and keyword arguments using *args, **kwargs: def foo(*args, **kwargs): pass, here foo accepts any number of positional and keyword arguments, i.e., the following calls are valid foo(1,name='Tom'), foo(1, 'bar', name='Tom', age=33)
  • To enforce keyword-only arguments using *: def foo(pos1, pos2, *, kwarg1): pass, here * means that foo only accepts keyword arguments after pos2, hence foo(1, 2, 3) raises TypeError but foo(1, 2, kwarg1=3) is ok.
  • To express no further interest in more positional arguments using *_ (Note: this is a convention only): def foo(bar, baz, *_): pass means (by convention) foo only uses bar and baz arguments in its working and will ignore others.
  • To express no further interest in more keyword arguments using \**_ (Note: this is a convention only): def foo(bar, baz, **_): pass means (by convention) foo only uses bar and baz arguments in its working and will ignore others.

Wrap Off

That's what you should know about the *args and **kwargs and how they should be used in Python.

If you learned from this tutorial, or it helped you in any way, please consider sharing and subscribing to our newsletter.

Please share this post and for more insightful posts on business, technology, engineering, history, and marketing, subscribe to our newsletter.

Get the Complete Code of Python Code Snippets on Github.

Connect with me.

Need an engineer on your team to grease an idea, build a great product, grow a business or just sip tea and share a laugh?