Asterisk Operator

What is the Asterisk / Star Operator (*) in Python?

The asterisk operator in Python has 6 different meanings:

  • (*)  Multiplication,
  • (**) Exponentiation,
  • (*)  Creating container types,
  • (*)  Unpacking 1: Define an arbitrary number of positional arguments,
  • (**) Unpacking 2: Define an arbitrary number of keyword arguments, and
  • (**) Unpacking a container type (e.g. dictionary).

After reading this article, you will have a solid understanding of a small but important topic in Python: the asterisk operator *.

** Reading time: 3:30 **

Before you start learning, let’s open your knowledge gap first. Go to my course web page and solve the code puzzle #43 (I have opened up this lecture temporarily so that you can access it for free):

… (This is you solving the Python puzzle) …

Welcome back! Do you feel confident using the asterisk (star) operator? No? I thought so!

When to use the star * operator in Python?

There are six different answers to this question:

1) Multiplying two values:

print(2 * 3)
# 6

This is how you have already used the star operator thousands of times in your own code.

2) Calculating the power of a value:

print(2 ** 3)
# 8

Using the star operator to exponentiate a value is a bit more unusual – but still very common. Simply use the expression x ** y to calculate “x to the power of y”.

3) Creating container data types:

lst = [999999] * 5
print(lst)
# [999999, 999999, 999999, 999999, 999999]

Creating lists by using the star operator is a handy feature. Keep it in mind and try to use it in your next projects (use it or lose it).

4) Creating a function with an arbitrary number of positional arguments:

def average(*args):
    return sum(args) / len(args)


print(average(999.0, 966.3, 988.2, 1344.5))
# 1074.5

Finally, we reached a much more interesting use case of the star operator which you should understand thoroughly.

How to ensure that a function can take an arbitrary number of arguments? The function “average” in the example shows you how to do this with your function argument (*args). The asterisk operator creates a sequence of values from an arbitrary number of positional arguments. It’s really this: it creates a new variable with the name “args” that is visible within the function. The variable is of type tuple as you can see here:

def average(*args):
    print(type(args))
    return sum(args) / len(args)


print(average(999.0, 966.3, 988.2, 1344.5))
# 1074.5

5) Creating a function with an arbitrary number of keyword arguments:

First of all, what are keyword arguments? They are function arguments with a name (unlike positional arguments).

def likes(**kwargs):
    for key in kwargs:
        print(key + " likes " + kwargs[key])


likes(Alice="Bob", Bob="Ann", Ann="Alice")
# Alice likes Bob
# Bob likes Ann
# Ann likes Alice

In the example, we pass three keyword arguments when calling the function “likes(…)” (with names: Alice, Bob, and Ann). The double asterisk operator ** before the variable “kwargs” packs all these arguments (and potentially more) into a dictionary named “kwargs”. Try it yourself: run print(type(kwargs)) within your function and the interpreter will tell you that the variable is of type ‘dict’.

Now, you can conveniently access the keyword arguments within your function (using the variable name “kwargs”).

We call case 4) and 5) UNPACKING of the arguments. Why unpacking? Because they are unpacked within the argument. What is the packed form then? You can get the packed form when leaving away the asterisk operator(s). For example, the values in “args” or “kwargs” are packed within a container data type (i.e., a tuple in case 4) and dictionary in case 5)).

6) Unpacking a dictionary

def likes(**kwargs):
    for key in kwargs:
        print(key + " likes " + kwargs[key])


dic = {"Alice" : "Bob",
       "Bob" : "Ann",
       "Ann" : "Alice"}
likes(**dic)
# Alice likes Bob
# Bob likes Ann
# Ann likes Alice

Now that you know about unpacking, it’s easy to see what is going on here. You create a dictionary ‘dic’. The dictionary contains the keyword arguments – but they are still packed within the dictionary. To unpack them, you use the double asterisk operator when calling the function. Think of it this way: If you wanted to define the values in the dictionary, you would write them without the curly bracket notation {}. To remove the bracket, you use the double asterisk operator **.

Train your unpacking skills!

At this point, you have learned about the asterisk (star) operator in Python. Use the asterisk operator to unpack a container data type such as a list or a dictionary.

Let’s practice unpacking a bit. Here is the most basic form of unpacking:

readers = ["Cata", "Brian", "Myu", "Joey"]

print(readers)
# ['Cata', 'Brian', 'Myu', 'Joey']

print(*readers)
# Cata Brian Myu Joey

As you can see, the asterisk operator basically removes the wrapper data type (i.e., the list). Here is how you can use simple unpacking when calling a function with positional arguments:

def say_hello(*args):
    for arg in args:
        print("hello " + arg)


readers = ["Cata", "Brian", "Myu", "Joey"]
say_hello(*readers)
"""
hello Cata
hello Brian
hello Myu
hello Joey
"""

The four list values “unfold” in the functional argument by passing it with *readers. Within the function argument, they exist in unpacked form.

In the function definition, you can see a second application of the asterisk operator: arbitrary arguments. Logically — if you put the asterisk operator before the argument name (*args) when defining the function — you tell him that the arguments are already unpacked. In other words, the expression *args contains the values in an unpacked form. Thus, the expression args (without the asterisk) refers to the packed form of these values. This is why you can use args in your function just like a normal list.

How does that look like for dictionaries?

elos = {"Alice" : 1988,
        "Bob" : 2253,
        "Frank" : 1574}

print(elos)
# {'Alice': 1988, 'Bob': 2253, 'Frank': 1574}

print(*elos)
# Alice Bob Frank

If you unpack a dictionary with the single asterisk operator, the result is the unpacked form of the dictionary’s keys.

Now, how do we unpack the dictionary’s (key, value) pairs (and not only the keys)? By using the double asterisk operator!

def print_masters(**kwargs):
    for key in kwargs:
        if kwargs[key] > 2000:
            print(str(key) + " " + str(kwargs[key]))


elos = {"Alice" : 1988,
        "Bob" : 2253,
        "Frank" : 1574}

print_masters(**elos)
# Bob 2253

Now, here is a nice way of using this feature to merge two dictionaries by unpacking both into a new dictionary…

elos_1 = {"Alice" : 1988,
        "Bob" : 2253}

elos_2 = {"Pete" : 1324,
        "Frank" : 1574}

elos = {**elos_1, **elos_2}
print(elos)
# {'Alice': 1988, 'Bob': 2253, 'Pete': 1324, 'Frank': 1574}

What a beautiful Python feature! 😀

Have you already solved the unpacking puzzle at my course page? If not, visit the page, scroll down and click the “Preview” button of lecture #43. Or get yourself lifetime access to the whole course as long as I keep the course at this price level (because I constantly keep adding value to the course)…

Frequently asked questions

What are keyword arguments in Python?

All function arguments have names (=keywords). When calling the function, you have two choices: use positional arguments or keyword arguments. In contrast to positional arguments, keyword arguments make the names explicit when calling the function. Using keyword arguments, you don’t need to care about the order of the arguments.

Here is an example:

def minus(a, b, c): # all arguments are named
    print(a - b - c)


# positional arguments:
minus(3,2,1)
# 0

# keyword arguments:
minus(c=1, b=2, a=3)
# 0 (keyword overwrites order / position)

Why is **kwargs used in Python?

The expression **kwargs is used when defining a function to indicate that you can call this function with an arbitrary number of keyword arguments. Here is an example:

def likes(**kwargs):
    for key in kwargs:
        print(str(key) + " likes " + str(kwargs[key]))


likes(Alice="Bob")
" Alice likes Bob"


likes(Alice="Bob", Bob="Alice")
"""
Alice likes Bob
Bob likes Alice
"""


likes(Alice="Bob", Bob="Alice", spam=42)
"""
Alice likes Bob
Bob likes Alice
spam likes 42
"""

As you can see, we can call the function with an arbitrary number of keyword arguments.

Where to go from here?

Before you can master numpy, you have to master Python first. I have created a free email course for you. The course guides you step-by-step to a deeper and deeper Python level of code understanding. Here is what my readers think:

Thank you for your newsletter. I find these newsletters highly informative.

Collen

As a fellow educator and fellow (former) Ph.D. student, I just wanted to let you know that I’m really impressed with your teaching materials.You’re doing a really good job!

Daniel