Day 01 - *args and **kwargs

When defining functions, we can use of two kinds of arguments, positional arguments and named arguments or keyword arguments.

Keyword arguments are normally used to declare arguments with a default value, which are then used in case we don’t pass it in when we make the call.

Positional Arguments

def multiply(a, b):
    print(a * b)

multiply(5, 4)

# Output: 20

Keyword Arguments

def keyword_multiply(a=2, b=9):
    print(a * b)

keyword_multiply(5, 4)
keyword_multiply(b=4, a=4)

# Output: 18
# Output: 20
# Output: 16
# Output: 4

Before explaining what are the *args and **kwargs we must emphasize that these variable names are only a convention and we can change their names when we need to, the important thing in this case are the * (asterisks)

Use of *args

We use *args for positional arguments, i.e. those that do not have a default value in the definition of the function

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

fun(1, 2, 3)
def fun(*args):

fun(1, 2, 3)

# Output: (1, 2, 3)

When using *args, all positional arguments are treated as a tuple.

Use of **kwargs

On the other hand we use the **kwargs for those arguments that have a default value in the definition of the function.

def fun(a=0, b=0, c=0):
    print(a, b, c)

fun(a=1, b=2, c=3)
def fun(**kwargs):

fun(a=1, b=2, c=3)

# Output: {"a": 1,"b": 2,"c": 3}

When we use double asterisk (**), the keyword arguments are treated as a dict.

This functionality allows us to pass an indefinite list of arguments, either positional or named, and treat them as 1 or 2 variables in the function, this is because just as we can combine both types of arguments when defining a function, we can make use of both variables in the same function.

Note that when working with both types of arguments, we must first define the positional arguments and then those that are named.

def fun(*args, **kwargs):

fun(1, 2, a=3, b=6)

# Output:
# (1, 2)
# {"a": 3, "b": 6}

Use of *args and **kwargs when calling a function

In the same way that we can pass multiple arguments and receive them in a single variable, we can make use of the asterisks (*) to do the process in the opposite way, in other words, we have a variable (tuple, list) with n values and pass it to a function with multiple arguments.

def func(a, b, c):
    print(f"a = {a}")
    print(f"b = {b}")
    print(f"c = {c}")

Using a single asterisk

numbers = [5, 4, 2]

# Output:
# a = 5
# b = 4
# c = 2

Using double asterisk

numbers = {"c": 4, "a": 6, "b": 9}

# Output:
# a = 6
# b = 9
# c = 4

In this case we could use the double asterisk although the function has no arguments with default values, since positional arguments can be treated in both ways.

Python Example

If you see the Python documentation, the print function makes use of *args, in its case and as I indicated at the beginning, it is not necessary that it is called this way.

print(*objects, sep=' ', end='\n', file=sys.stdout, flush=False)

We can print multiple values by passing them to the function each separated by a comma or even using the *args

print("Hello", "World")

values = ["Hello", "World"]

# Output:
# Hello World
# Hello World

Go to the Challenge

Go to the Solution