If you ever go through the documentation of a Python library, it’s inevitable to notice the use of * or ** in several places.
But, what do they (* and **) do?
We’ll learn 7 use cases where * and ** come in handy including the cases you notice in documentations.
The use cases are best explained with examples so let’s jump right into it.
1. Call a function with iterables
Let’s say you define a function that takes 5 positional arguments, adds them together, and returns the sum.
# define the function
def calculate_sum(a, b, c, d, e):
return a + b + c + d + e
# call the function
result = calculate_sum(1, 4, 3, 2, 6)
print(result)
16
If the values passed to the function as arguments are stored in an iterable (e.g. list), you can call the function using the list directly but you need to use * as shown below:
# call the function
numbers = [1, 4, 3, 2, 6]
calculate_sum(*numbers)
print(result)
16
If you try to call the function as calculate_sum(numbers)
, Python will complain, raising a TypeError
. What * does here is to unpack the values in the iterable, sometimes referred to as argument unpacking.
It is important to note that the number of values in the numbers
list must be equal to the number of arguments the function takes, which is 5 in this case. Otherwise, we’ll get a TypeError
.
If you’d also like to learn more about Pandas, visit my course 500 Exercises to Master Python Pandas.
2. Call a function with dictionaries
This use case is similar to the previous one. In the previous example, the function only has positional arguments. In the case of a function with keyword arguments, we can still do argument unpacking but with * instead of .
# define the function
def calculate_mass(density, length=1, width=1, height=1):
return density * length * width * height
# call the function
density = 20
mass = calculate_mass(density, 2, 3, 5)
print(mass)
600
The function calculates the mass of an object using its density, length, width, and height. Let’s say the measures are stored in a Python dictionary. We can use the dictionary directly to call the function as shown below:
# call the function
density = 20
measures = {
"length": 2,
"width": 3,
"height": 5
}
calculate_mass(density, **measures)
600
Similar to the first example, if we try to call it as calculate_mass(density, measures)
, we’ll get a TypeError
. This is another example of argument unpacking.
3. Define a function with any number of positional arguments
You define a function that sums up the given values but you don’t want to put a constraint on the number of values to pass as arguments. Instead, you want it to be dynamic and sums up any number of given values.
Here is how we can define this function:
# define the function
def calculate_sum(*args):
result = 0
for i in args:
result += i
return result
The *args
expression packs the arguments passed to the function allowing us to use any number of arguments or an iterable to call the function.
Here are different ways of calling this function:
# calling with 2 values
calculate_sum(3, 4)
7
# calling with a list
my_list = [1, 4, 5, 10, 20]
calculate_sum(*my_list)
40
# calling with a value and a list
my_list = [10, 20, 30]
calculate_sum(5, *my_list)
65
In the case of using an iterable to call the function, we still need to put a * when calling the function.
Note on positional and keyword arguments:
Positional arguments are declared by a name only. When a function is called, values for positional arguments must be given. Otherwise, we will get an error.
Keyword arguments are declared by a name and a default value. If we do not specify the value for a keyword argument, it takes the default value.
4. Define a function with any number of keyword arguments
This one is similar to the previous use case but we’ll create a function that takes keyword arguments.
# define the function
def greet(name, **kwargs):
greeting = f"Hello, {name}.n"
if kwargs:
greeting += "Here are the things I know about you:n"
for key, value in kwargs.items():
greeting += f" {key.title()}: {value}n"
return greeting
The function greets people given their name. If it’s called with additional keyword arguments of information about the people, the function prints them as well.
The **kwargs
expression allows us to pass any number of keyword arguments when calling the function.
Here are different ways of calling this function:
# calling with the name (positional argument) only
print(greet("John"))
# output
Hello, John.
# calling with adding some keyword arguments
print(greet("Jane", age=34, job="doctor", hobby="chess"))
# output
Hello, Jane.
Here are the things I know about you:
Age: 34
Job: doctor
Hobby: chess
# calling with adding some keyword arguments as a dictionary
ashley = {
"age": 27,
"profession": "athlete",
"hobby": "reading"
}
print(greet("Ashley", **ashley))
# output
Hello, Ashley.
Here are the things I know about you:
Age: 27
Profession: athlete
Hobby: reading
In the case of passing the keyword arguments as a dictionary, we need to put a ** when calling the function.
5. Combine dictionaries
We can use ** for combining dictionaries.
ages = {
"John": 34,
"Jane": 36
}
new_items = {
"Matt": 28,
"Ashley": 24
}
ages = {**ages, **new_items}
print(ages)
{'John': 34, 'Jane': 36, 'Matt': 28, 'Ashley': 24}
In this case, using ages = {ages, new_items}
will raise a TypeError
as well.
6. Packing values into iterables
Let’s say we have a list with multiple values. We want to assign a value from this list to another variable and assign the remaining ones to a different variable. It’ll be more clear when we go through the examples below:
first, *others = [3, 5, 1, 10, 24]
print(first)
print(others)
# output
3
[5, 1, 10, 24]
The first value is assigned to a variable named first
and the remaining ones are packed into another list named others
.
We can also use it as shown in the example below:
first, *others, last = [3, 5, 1, 10, 24]
print(first)
print(others)
print(last)
# output
3
[5, 1, 10]
24
This use case might be helpful when working with functions that return multiple values. Here is an example:
# define the function
def my_func(a, b, c, d, e):
sum_1 = a + b
sum_2 = a + b + c
sum_3 = a + b + c + d
sum_4 = a + b + c + d + e
return sum_1, sum_2, sum_3, sum_4
# call the function
first_sum, *other_sums = my_func(1, 3, 5, 2, 6)
print(first_sum)
print(other_sums)
# output
4
[9, 11, 17]
The my_func
function returns a tuple with 4 values. The first one is assigned to a variable named first_one
and the others to a list named other_sums
.
Final words
As demonstrated in the examples we’ve done, the * and ** are quite useful in Python. We can use them for argument packing and unpacking.
They’re also used when defining and calling functions to add more flexibility and versatility.
You can become a Medium member to unlock full access to my writing, plus the rest of Medium. If you already are, don’t forget to subscribe if you’d like to get an email whenever I publish a new article.
Thank you for reading. Please let me know if you have any feedback.