What is unpacking in Python?

Discover unpacking in Python: syntax, practical examples, destructuring of tuples, lists and dictionaries. Complete guide to mastering this technique.
9 min read
Believemy logo

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:

PYTHON
# Unpacking a tuple
coordinates = (48.8566, 2.3522)
latitude, longitude = coordinates

print(latitude)   # 48.8566
print(longitude)  # 2.3522

Without unpacking, you would have to write:

PYTHON
# 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:

PYTHON
# Unpacking a list
colors = ["red", "green", "blue"]
first, second, third = colors

print(first)   # red
print(second)  # green
print(third)   # blue
Warning

The 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:

PYTHON
# Swapping variables using unpacking
a = 10
b = 20

a, b = b, a

print(a)  # 20
print(b)  # 10

In 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

PYTHON
# 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]
PYTHON
# 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

PYTHON
# 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)    # 16
Good to know

The 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:

PYTHON
# 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:

PYTHON
# 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

PYTHON
# 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:

PYTHON
# 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.

PYTHON
# 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:

PYTHON
# *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
PYTHON
# **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:

PYTHON
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:

PYTHON
# Unpacking with enumerate
fruits = ["apple", "banana", "cherry"]
for index, fruit in enumerate(fruits):
    print(f"{index}: {fruit}")
# 0: apple
# 1: banana
# 2: cherry
PYTHON
# 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
PYTHON
# 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:

PYTHON
# 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']
PYTHON
# 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

PYTHON
# 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:

PYTHON
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:

PYTHON
# 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

PracticeRecommendation
Number of variablesMake sure the number of variables matches the number of elements, or use *
Ignored variablesUse _ for values you don't use
Nested unpackingDon't nest beyond 2 levels to maintain readability
Variable namingGive explicit names that reflect the meaning of the data
Variable swappingPrefer a, b = b, a over a temporary variable
Dict mergingUse {**d1, **d2} or the | operator (Python 3.9+)
Good to know

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

PYTHON
# ❌ 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)
PYTHON
# ❌ 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

Question

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.

 

Question

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.

 

Question

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.

 

Question

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.

Related terms

Discover our python glossary

Browse the terms and definitions most commonly used in development with Python.

Share this article

Want to help us? Share this article on your networks or even better: on your site, in an article or in your newsletter.