Python functions: args and kwargs

Earlier we saw how to write functions in python and how to call them in our program. For those functions, the number of inputs or arguments were defined. They took fixed number of positional or keyword arguments or had a default value assigned to one or more of the arguments.

But how to handle situations where we want to write a function wherein we do not know how many arguments we are going to give.
In these conditions, the *args and **kwargs functionality is used.

We will first try to understand how each of these work.

*args

When we include *args in the definition of a function, it means that we can give it any number of keyword arguments to it.

To understand how *args work, we will make a function that concatenates any string arguments given to it.

But let’s do it stepwise. We will first see in what form the *args are interpreted inside the function. We will just make our first version of the function that prints out the data type of the args object.

Python
def add_str(*args):
    print(f'The "args" are read as {type(args)} type of object.')
    
add_str(2,3,4,5)
Output
The "args" are read as <class 'tuple'> type of object.

We see above that the function combines all the positional arguments of the function under *args as tuple. This gives us the method with which to use them. Now we will modify this function that would concatenate the strings. If a number is present we will convert it to string and then concatenate.

To do this:

  • an empty string is created and each position argument is iterated over and added to the empty string.
  • we will use str() function to convert any numerical in the args.
  • str() function does not have any effect when given a string object as argument. So there is no need to check the type of the element in arg.
  • we will insert a space character after each arg added.
Python
def add_str(*args):
    res = ''
    for arg in args:
        res = res + str(arg) + ' '
        
    return res

add_str('a', 'fg', 'htw', 'c', 4, 'g5', 68)
Output
'a fg htw c 4 g5 68 '

In summary, the *args arguments in a function is interpreted as a tuple inside a functions. Each element of the tuple is the postional argument given to the function.

Now we will see how the **kwargs are interpreted in the python function.

**kwargs

Only keyword arguments can be passed under **kwargs.

Python

Python
def add_str2(**kwargs):
    print(f'The "kwargs" are read as {type(kwargs)} type of object.')

add_str2(a=2, b=4, c='teak', d = 'wood')
Output
The "kwargs" are read as <class 'dict'> type of object.

So, the **kwargs are read as a dictionary in contrast to a tuple in case of *args.

Now, let’s write a function that does the same thing of concatenating the number/strings given to the function.

Python
def add_str2(**kwargs):
    res = ''
    for key in kwargs:
        res = res + str(kwargs[key]) + ' '
        
    return res

add_str2(a=2, b=4, c='teak', d = 'wood')
Output
'2 4 teak wood '

*args and **kwargs can be used when a function can be given optional arguments.

For example, the pyplot.plot function has following syntax for calling:

Python
matplotlib.pyplot.plot(*args, scalex=True, scaley=True, data=None, **kwargs)

You can see that the function takes regular keyword arguments which have default values, the *args and also **kwargs.

One example of its usage is:

Python
plot(x, y, 'go--', linewidth=2, markersize=12)

Here, you can see that:

  • none of the regular keyword arguments is given while calling the function. So the default values for these keyword arguments will be taken by the function.
  • the arguments xy and go-- will be taken by the function under *args.
  • the keyword arguments linewidth and markersize will be taken under **kwargs.

Reference: The matplotlib code was taken from its documentation page

Using exact names for *args and **kwarg not necessary

We can use any name for *args and *kwargs. The only important thing is the single asterisk (*) or the double asterisk (**).

Single (*) as in *name will stand for positional arguments *args.

Double (**) as in **name will stand for the keyword arguments **kwargs.