Python - Understanding *args And **kwargs

Introduction

The article explains one of the confusing magic variables in Python *args and **kwargs. In Python, functions are building blocks that can take zero or n number of arguments. The *args and **kwargs allow developers to pass an unspecified number of arguments. The article covers

  • Purpose of *args and understanding with examples
  • Purpose of **kwargs and understanding with examples
  • Where to use them

Purpose of *args

First and foremost, it’s better to understand the difference between a Positional argument and a Keyword argument. Positional argument means arguments are declared by name, and keyword argument means it is declared by name and a default value.

def concat(x, y="B"):
    return x + y

in the function, x is positional, and y is the keyword argument.  

*args is used when we are unsure about the number of arguments we want to pass as a function parameter. This syntax allows us to pass any number of arguments to the function.

* operator indicates that all positional arguments passed to the function are packed as a list/tuple. Please note that it is not necessary to write *args and **kwargs, only * is required. We can very well use any word instead of args and kwargs.

Let’s understand by the basic example of printing all the elements passed to the function.

def learn(*args):
    for e in args:
        print(e)

learn("A", "B", "C") #  A B C

In the above function replacing args with param.

def learn(*params):
    for e in params:
        print(e)

learn("A", "B", "C")

The same result is returned in both the functions 

Let’s look at a slightly more meaningful example of a string concatenation, the function accepts two parameters and concatenates them

def concat(x, y):
    return x + y

print(concat("A", "B")) 

Output

AB

Using *args approach

def concat(*args):
    result = ""
    for s in args:
        result = result + s
    return result

print(concat("A", "B", "C", "D"))

Output

ABCD

Purpose of **kwargs

**kwargs can be read as keyword arguments, it accepts keyword-based Python dictionaries.

Just like in the case of *args, we can very well replace kwargs with any other word, but I recommend sticking to them for a better code readability perspective. Let’s understand with a basic example.

def kwargsDemo(**kwargs):
    print(kwargs)

kwargsDemo(car='BMW', model='2022')

# {'car': 'BMW', 'model': '2022'}

Iterating through the dictionary items

def kwargsDemo(**kwargs):
    for car, model in kwargs.items():
        print(car, model)

kwargsDemo(car='BMW', model='2022')
#car BMW
#model 2022

Note
If the function needs to accept multiple parameters along with *args and **kwargs, ensure that *args && **kwargs are the last parameters of the parameter list, else an error will be thrown.

When to use them

*args and **kwargs are used mostly while creating decorators with arguments, decorator in python is a function when it’s used with any function it adds functionality on the top of it.

def printAll(func):
    def inner(*args, **kwargs):
        func(*args, **kwargs)
    return inner

@printAll
def take(messages):
    print(messages)
    
print("Hello")
print("Hello", "World")

Output

Hello and Hello World

Summary

Usage of magic variables is not only restricted to decorators but they can also be used during Monkey Patching, Monkey Patching means modifying the code at runtime or dynamically adding the behavior. But we should be used judiciously in normal circumstances as it can create confusion during debugging.