*args and **kwargs in Python

Python provides some handy ways through which we could make a function take a variable number of arguments. *args and **kwargs do just that.

*args -> Represents a List / Tuple of positional arguments to be passed to any function

**kwargs -> Represents a Dictionary of keyword arguments to be passed to any function


Purpose of *args

*args is commonly used when you’re not sure about the number of arguments that you want to pass as function parameters, when you define the function. So essentially, this type of syntax allows us to pass an arbitrary number of arguments to the function, the exact number being determined at runtime.

There are two cases where the * (star) operator differs in meaning.

Case 1 : In a function definition

Here, the * operator is used to pack the arguments into a tuple/list (which contains all the positional) arguments passed to the function. Hence, we use *args in the definition to signity that all the positional arguments passed to the function are packed into a list/tuple called args (Any other name can be given, but it is common practice to write *args to signify that argument packing is used)

def find_average(*args):
    total = 0
    print('Packed Argument Tuple ->', args)
    for i in args:
        total += i
    return total / len(args)


print('Average ->', find_average(1, 2, 3, 4, 5))

Output

Packed Argument Tuple -> (1, 2, 3, 4, 5)
Average -> 3.0

Case 2: In a function call

Here, the * operator is used to unpack the corresponding list/tuple passed to it, or even a generator.

a = [1, 2, 3]
print(*a)

Output

1 2 3

This could be useful if you want an iterable to be expanded only the corresponding function is called.


Combining Case1 and Case2 to use *args

Here is an example using both Case1 and Case2 to compute the maximum of a list being unpacked and passed into a function, that takes a variable number of arguments.

def compute_maximum(*args):
    maximum = 0
    for i in args:
        if i > maximum:
           maximum = i
    return maximum

a = [4, 5, 10, 14, 3]
print('Maximum ->', compute_maximum(*a))

Output

Maximum -> 14

Purpose of **kwargs

Here, the ** operator is used in a way similar to the previous situation, but this is applied exclusively to pack keyword arguments passed to a function into a Dictionary. The **kwargs idiom only applies to a function definition, and unlike *args, does not have any special meaning in a function call.

Here is an example to illustrate the purpose of **kwargs

def find_average(**kwargs):
    total = 0
    print('Keyword Argument Dictionary ->', kwargs)
    for key, value in kwargs.items():
        total += value
    return total / len(kwargs.items())


print('Average ->', find_average(first=1, second=2, third=3, fourth=4, fifth=5))

Output

Keyword Argument Dictionary -> {'first': 1, 'second': 2, 'third': 3, 'fourth': 4, 'fifth': 5}
Average -> 3.0

The * operator can be used here to unpack the **kwargs and get all the keys/values passed to the keyword Dictionary

>>> print(*kwargs)
first second third fourth fifth
>>> print(*kwargs.values())
1 2 3 4 5

Conclusion

This article helped us gain a deeper understanding of how *args and **kwargs can be used in function definitions to get a variable number of positional / keyword arguments and manipulate them, and how programmers use it in common practice for writing easy to use functions.

References

StackOverflow : https://stackoverflow.com/questions/3394835/use-of-args-and-kwargs