Definition of unpacking in Python
Unpacking (also known as destructuring) is a fundamental feature of Python that allows you to extract elements from an iterable (such as a tuple, a list, a set or a dict) and assign them simultaneously to multiple variables in a single statement. It is one of the most elegant techniques in the language, and it is omnipresent in professional Python code.
If you want to deepen your understanding of this concept and many other essential topics, our complete Python course will guide you step by step through your learning journey.
Instead of manually accessing each element by its index, unpacking allows you to write more concise, readable and Pythonic code. Let's explore together how this technique works in detail.
Basic unpacking: tuples and lists
Unpacking a tuple
The most common form of unpacking consists of assigning the elements of a tuple to distinct variables:
# Unpacking a tuple
coordinates = (48.8566, 2.3522)
latitude, longitude = coordinates
print(latitude) # 48.8566
print(longitude) # 2.3522Without unpacking, you would have to write:
# Without unpacking (less elegant)
coordinates = (48.8566, 2.3522)
latitude = coordinates[0]
longitude = coordinates[1]The difference is notable: unpacking makes the code much more readable and expressive.
Unpacking a list
Unpacking works exactly the same way with list:
# Unpacking a list
colors = ["red", "green", "blue"]
first, second, third = colors
print(first) # red
print(second) # green
print(third) # blueThe number of variables on the left side of the = sign must match exactly the number of elements in the iterable, unless you use the * operator (which we will cover below). Otherwise, Python will raise a ValueError.
Swapping variables
Unpacking enables a famous Python trick: swapping two variables without a temporary variable:
# Swapping variables using unpacking
a = 10
b = 20
a, b = b, a
print(a) # 20
print(b) # 10In many other languages, this operation would require a temporary intermediate variable. In Python, unpacking makes this operation trivial.
Extended unpacking with the * operator
Since Python 3, the * operator (sometimes called the "splat" or "star" operator) allows you to capture a variable number of elements during unpacking. This is called extended unpacking.
Capturing the beginning and the end
# Capture the first element and the rest
grades = [18, 15, 12, 9, 14, 16]
first, *rest = grades
print(first) # 18
print(rest) # [15, 12, 9, 14, 16]# Capture the last element
grades = [18, 15, 12, 9, 14, 16]
*beginning, last = grades
print(beginning) # [18, 15, 12, 9, 14]
print(last) # 16
Capturing the middle
# Capture the first, last and middle
grades = [18, 15, 12, 9, 14, 16]
first, *middle, last = grades
print(first) # 18
print(middle) # [15, 12, 9, 14]
print(last) # 16The variable preceded by * will always be of type list, even if it contains only one element or no elements (empty list).
Ignoring values with _
The convention in Python is to use the _ (underscore) character to ignore values you don't need:
# Ignoring certain values
name, _, age, _ = ("Alice", "Dupont", 30, "Paris")
print(name) # Alice
print(age) # 30
# Ignoring multiple values with *_
first, *_, last = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
print(first) # 1
print(last) # 10
Unpacking dictionaries
Unpacking dict has its own particularities. By default, unpacking iterates over the keys of the dictionary:
# Unpacking dictionary keys
person = {"name": "Alice", "age": 30, "city": "Paris"}
key1, key2, key3 = person
print(key1) # name
print(key2) # age
print(key3) # city
Unpacking values and pairs
# Unpacking values
person = {"name": "Alice", "age": 30, "city": "Paris"}
v1, v2, v3 = person.values()
print(v1) # Alice
print(v2) # 30
print(v3) # Paris
# Unpacking key-value pairs
for key, value in person.items():
print(f"{key}: {value}")
# name: Alice
# age: 30
# city: Paris
The ** operator for dictionaries
The ** operator (double splat) allows you to "unpack" a dictionary, primarily to merge dictionaries or pass keyword arguments to a function:
# Merging dictionaries with **
defaults = {"color": "blue", "size": "M", "stock": 10}
customization = {"color": "red", "price": 29.99}
product = {**defaults, **customization}
print(product)
# {'color': 'red', 'size': 'M', 'stock': 10, 'price': 29.99}Notice that the color key from the second dictionary overrides the one from the first. Order matters.
# Passing keyword arguments with **
def create_profile(name, age, city):
return f"{name}, {age} years old, lives in {city}"
info = {"name": "Alice", "age": 30, "city": "Paris"}
result = create_profile(**info)
print(result) # Alice, 30 years old, lives in Paris
Unpacking in functions
*args and **kwargs parameters
Unpacking is at the heart of the variadic parameter mechanism in Python. When you define a function with def, you can use *args and **kwargs:
# *args captures positional arguments into a tuple
def total(*args):
result = 0
for number in args:
result += number
return result
print(total(1, 2, 3)) # 6
print(total(10, 20, 30, 40)) # 100# **kwargs captures keyword arguments into a dictionary
def display_info(**kwargs):
for key, value in kwargs.items():
print(f"{key} = {value}")
display_info(name="Alice", age=30, city="Paris")
# name = Alice
# age = 30
# city = Paris
Unpacking when calling a function
You can also use * and ** to "unpack" arguments when calling a function:
def calculate_volume(length, width, height):
return length * width * height
# Unpacking a list as positional arguments
dimensions = [3, 4, 5]
volume = calculate_volume(*dimensions)
print(volume) # 60
# Unpacking a dictionary as keyword arguments
dims = {"length": 3, "width": 4, "height": 5}
volume = calculate_volume(**dims)
print(volume) # 60
Unpacking in loops
Unpacking is particularly useful in loops, especially with enumerate and zip:
# Unpacking with enumerate
fruits = ["apple", "banana", "cherry"]
for index, fruit in enumerate(fruits):
print(f"{index}: {fruit}")
# 0: apple
# 1: banana
# 2: cherry# Unpacking with zip
names = ["Alice", "Bob", "Charlie"]
ages = [30, 25, 35]
for name, age in zip(names, ages):
print(f"{name} is {age} years old")
# Alice is 30 years old
# Bob is 25 years old
# Charlie is 35 years old# Unpacking nested tuples
points = [(1, 2), (3, 4), (5, 6)]
for x, y in points:
print(f"x={x}, y={y}")
# x=1, y=2
# x=3, y=4
# x=5, y=6
Nested unpacking
Python supports unpacking of nested structures, which is extremely powerful for manipulating complex data:
# Nested unpacking
data = ("Alice", (30, "Paris"), ["Python", "JavaScript"])
name, (age, city), languages = data
print(name) # Alice
print(age) # 30
print(city) # Paris
print(languages) # ['Python', 'JavaScript']# Nested unpacking in a loop
employees = [
("Alice", ("Developer", 45000)),
("Bob", ("Designer", 40000)),
("Charlie", ("Manager", 55000)),
]
for name, (position, salary) in employees:
print(f"{name} - {position}: ${salary}")
# Alice - Developer: $45000
# Bob - Designer: $40000
# Charlie - Manager: $55000
Advanced use cases
Unpacking in comprehensions
# Unpacking in a list comprehension
pairs = [(1, "a"), (2, "b"), (3, "c")]
result = [f"{num}-{letter}" for num, letter in pairs]
print(result) # ['1-a', '2-b', '3-c']
Unpacking with namedtuples and dataclasses
Unpacking works perfectly with namedtuple and dataclass:
from collections import namedtuple
Point = namedtuple("Point", ["x", "y", "z"])
p = Point(1, 2, 3)
x, y, z = p
print(x, y, z) # 1 2 3
Combining * in literals
Since Python 3.5+, you can use * and ** directly in list, tuple and dictionary literals:
# Combining lists with *
list1 = [1, 2, 3]
list2 = [4, 5, 6]
combined = [*list1, *list2, 7, 8]
print(combined) # [1, 2, 3, 4, 5, 6, 7, 8]
# Creating a combined tuple
t = (*list1, *list2)
print(t) # (1, 2, 3, 4, 5, 6)
# Combining sets
set1 = {1, 2, 3}
set2 = {3, 4, 5}
combined = {*set1, *set2}
print(combined) # {1, 2, 3, 4, 5}
Best practices
| Practice | Recommendation |
|---|---|
| Number of variables | Make sure the number of variables matches the number of elements, or use * |
| Ignored variables | Use _ for values you don't use |
| Nested unpacking | Don't nest beyond 2 levels to maintain readability |
| Variable naming | Give explicit names that reflect the meaning of the data |
| Variable swapping | Prefer a, b = b, a over a temporary variable |
| Dict merging | Use {**d1, **d2} or the | operator (Python 3.9+) |
Unpacking is a technique at the heart of the Python philosophy. It makes code more concise and expressive. Don't hesitate to use it whenever you manipulate iterable data structures.
Common mistakes to avoid
# ❌ Error: too many values to unpack
a, b = (1, 2, 3)
# ValueError: too many values to unpack (expected 2)
# ✅ Solution: use *
a, b, *_ = (1, 2, 3)
# ❌ Error: not enough values
a, b, c = (1, 2)
# ValueError: not enough values to unpack (expected 3, got 2)
# ✅ Solution: adjust the number of variables
a, b = (1, 2)# ❌ Error: two * operators in the same unpacking
*a, *b = [1, 2, 3, 4, 5]
# SyntaxError: multiple starred expressions in assignment
# ✅ Solution: only one * is allowed
*a, b = [1, 2, 3, 4, 5]
Frequently asked questions
What is the difference between * and ** in unpacking?
The * operator (single star) is used for unpacking sequential iterables like list, tuple and set. It allows you to capture multiple elements into a list or unpack a sequence as positional arguments. The ** operator (double star) is exclusively reserved for dict: it unpacks key-value pairs as keyword arguments or allows you to merge dictionaries.
Does unpacking work with any iterable?
Yes, unpacking works with any iterable object in Python: tuples, lists, strings, sets, dictionaries, generators (created with yield), results from enumerate, zip, and even your own custom iterable objects created with class. The only requirement is that the object implements the iteration protocol.
Does unpacking have an impact on performance?
Unpacking in Python is a highly optimized operation at the interpreter level. Its cost is negligible and comparable to index access. In the vast majority of cases, you won't notice any performance difference. Always prefer code readability: unpacking makes code clearer and more maintainable, which is far more important than micro-optimizations.
How can I learn to master unpacking and Python in general?
Unpacking is one of the many elegant techniques that make Python powerful. To master this concept as well as the entire language in a structured way, we recommend following our dedicated Python course on Believemy. You will progressively learn all the essential concepts, from basics to advanced topics, with practical exercises at every step.