10 Examples to Master *args and **kwargs in Python | by Soner Yıldırım | Towards Data Science

Functions are building blocks in Python. They take zero or more arguments and return a value. Python is pretty flexible in terms of how arguments are passed to a function. The *args and **kwargs make it easier and cleaner to handle arguments.
The important parts are “*” and “**”. You can use any word instead of args and kwargs but it is the common practice to use the words args and kwargs. Thus, there is no need for unnecessary adventures.
In this post, we will go over 10 examples that I think will make the concept of *args and **kwargs crystal clear.
Consider the following function that sums up two numbers.
def addition(a, b):   return a + bprint(addition(3,4))7
This function sums up only two numbers. What if we want a function that sums up three or four numbers? We may not even want to put a constraint on the number of arguments that passes to the function.
In such cases, we can use *args as parameter.
*args allow a function to take any number of positional arguments.
def addition(*args):   result = 0   for i in args:      result += i   return result
The parameters passed to the addition function are stored in a tuple. Thus, we can iterate over the args variable.
print(addition())0print(addition(1,4))5print(addition(1,7,3))11
Before the second example, it is better to explain the difference between a positional argument and a key word argument.
Positional arguments are declared by a name only.
Keyword arguments are declared by a name and a default value.
When a function is called, values for positional arguments must be given. Otherwise, we will get an error.
If we do not specify the value for a keyword argument, it takes the default value.
def addition(a, b=2): #a is positional, b is keyword argument   return a + bprint(addition(1))3def addition(a, b): #a and b are positional arguments   return a + bprint(addition(1))TypeError: addition() missing 1 required positional argument: 'b'
We can do the second example now. It is possible to use the *args and named variables together. The following function prints the passed arguments accordingly.
def arg_printer(a, b, *args):   print(f'a is {a}')   print(f'b is {b}')   print(f'args are {args}')arg_printer(3, 4, 5, 8, 3)a is 3b is 4args are (5, 8, 3)
The first two values are given to a and b. The remaining values are stored in the args tuple.
Python wants us to put keyword arguments after positional arguments. We need to keep that in mind when calling a functions.
Consider the following example:
arg_printer(a=4, 2, 4, 5)SyntaxError: positional argument follows keyword argument
If we assign a value to a positional argument, it becomes a keyword argument. Since it is followed by positional arguments, we get a SyntaxError.
In the following function, the option is a keyword argument (it has a default value).
def addition(a, b, *args, option=True):   result = 0   if option:      for i in args:      result += i      return a + b + result   else:      return result
This function performs addition operation if option is True. Since the default value is True, the function returns the sum of the arguments unless option parameter is declared as False.
print(addition(1,4,5,6,7))23print(addition(1,4,5,6,7, option=False))0
The **kwargs collect all the keyword arguments that are not explicitly defined. Thus, it does the same operation as *args but for keyword arguments.
**kwargs allow a function to take any number of keyword arguments.
By default, **kwargs is an empty dictionary. Each undefined keyword argument is stored as a key-value pair in the **kwargs dictionary.
def arg_printer(a, b, option=True, **kwargs):   print(a, b)   print(option)   print(kwargs)arg_printer(3, 4, param1=5, param2=6)3 4True{'param1': 5, 'param2': 6}
We can use both *args and **kwargs in a function but *args must be put before **kwargs.
def arg_printer(a, b, *args, option=True, **kwargs):   print(a, b)   print(args)   print(option)   print(kwargs)arg_printer(1, 4, 6, 5, param1=5, param2=6)1 4(6, 5)True{'param1': 5, 'param2': 6}
We can pack and unpack variables using *args and **kwargs.
def arg_printer(*args):   print(args)
If we pass a list to the function above, it will stored in args tuple as one single element.
lst = [1,4,5]arg_printer(lst)([1, 4, 5],)
If we put an asterisk before lst, the values in the list will be unpacked and stored in args tuple separately.
lst = [1,4,5]arg_printer(*lst)(1, 4, 5)
We can pass multiple iterables to be unpacked together with single elements. All values will be stored in the args tuple.
lst = [1,4,5]tpl = ('a','b',4)arg_printer(*lst, *tpl, 5, 6)(1, 4, 5, 'a', 'b', 4, 5, 6)
We can do the packing and unpacking with keyword arguments as well.
def arg_printer(**kwargs):   print(kwargs)
But the iterable that is passed as keyword arguments must be a mapping such as a dictionary.
dct = {'param1':5, 'param2':8}arg_printer(**dct){'param1': 5, 'param2': 8}
If we also pass additional keyword arguments together with a dictionary, they will combined and stored in the kwargs dictionary.
dct = {'param1':5, 'param2':8}arg_printer(param3=9, **dct){'param3': 9, 'param1': 5, 'param2': 8}
To summarize what we have covered:
There are two types of arguments in a function which are positional arguments (declared by a name only) and keyword arguments (declared by a name and a default value).
When a function is called, values for positional arguments must be given. Keywords arguments are optional (they take the default value if not specified).
*args collects the positional arguments that are not explicitly defined and store them in a tuple
**kwargs does the same as *args but for keyword arguments. They are stored in a dictionary because keyword arguments are stored as name-value pairs.
Python does not allow positional arguments to follow keyword arguments. Thus, we first declare positional arguments and then keyword arguments.
Thank you for reading. Please let me know if you have any feedback.