Today, we’re expanding our new concept series by building on the concept of an iterable. Specifically, we’ll be looking at a feature of iterables called iterable unpacking. Let’s get into it!
Table of Contents
- Concept Overview
- Common Use Cases
- How Does Iterable Unpacking Work With Custom Iterables?
- Python Version History
- Unpacking More Concepts
Concept Overview
In Python, iterable unpacking refers to the ability to extract the contents of an iterable into a sequence of variables.
To illustrate iterable unpacking, imagine that you have a list where the elements are in a predictable order, such as a list containing a student’s ID number as well as their first and last name. When processing this list, we might want to move each element into a variable with a reasonable name, rather than accessing the indices directly, as follows:
student = [3, "Jeremy", "Grifski"] identifier = student[0] first_name = student[1] last_name = student[2]
Naturally, this is a bit cumbersome, so the Python developers came up with a much nicer syntax called iterable unpacking:
student = [3, "Jeremy", "Grifski"] identifier, first_name, last_name = student
Later, if you decide to expand your dataset to include other information about each student, you might convince yourself that the only solution is to fall back on indexing and slicing:
student = [3, "Jeremy", "Grifski", 175, 3.2] identifier, first_name, last_name, data = student[0], student[1], student[2], student[3:]
Fortunately, you can save yourself a lot of time by using the iterable unpacking operator, *
, as follows:
student = [3, "Jeremy", "Grifski", 175, 3.2] identifier, first_name, last_name, *data = student
In other words, aside from the first three elements in the list, everything else will be stored in a new list in data
.
Next, we’ll talk about a few places where iterable unpacking is commonly used.
Common Use Cases
The very first place that iterable unpacking comes to mind for me is in the *args
syntax you sometimes see as function parameter, such as in max()
and min()
. The whole idea being that you can pass in any number of values and they all get captured in the args
variable, much like the following:
identifier, first_name, last_name, *args = 3, "Jeremy", "Grifski", 175, 3.2
Another place that this comes to mind for me is when you want a convenient way to swap variables. Normally, you have to introduce a temporary variable as follows:
first = "Robert" second = "Allen" # performs the swap temp = first first = second second = temp
With iterable unpacking, the syntax could not be cleaner:
first = "Robert" second = "Allen" # performs the swap first, second = second, first
In addition, another really common use of iterable unpacking is during looping. For example, sometimes folks like to approximate a for loop from their favorite C-style languages by using enumerate()
. What enumerate()
does is craft a sequence of tuples where the first element is the index and the second element is the data. Because the order is constant, we can take advantage of iterable unpacking:
watchlist = ["Loki", "Attack on Titan", "Vinland Saga"] for index, show in enumerate(watchlist): print(index, show) # prints # 0 Loki # 1 Attack on Titan # 2 Vinland Saga
A similar trick can be used when you’re iterating over a dictionary using the items()
method. Once you start to notice this trick, you’ll start seeing it everywhere.
Lastly, you might also know that Python let’s you return multiple values from a function by wrapping them in a tuple. When this happens, you might be tempted to store the tuple outright and index it for the values you need. Instead, I prefer to use iterable unpacking to get nice variables as follows
def grade_range(scores): return min(scores), max(scores) grades = [71, 93, 54, 99, 80] worst_grade, best_grade = grade_range(grades)
How cool is that? Next, we’ll look at how iterable unpacking works with custom iterables.
How Does Iterable Unpacking Work With Custom Iterables?
Previously, you may recall that we created a couple of our own custom iterables. Naturally, I’m interested in if these same iterables support iterable unpacking. To start, we’ll use a custom iterable that implements the __iter__()
special method.
import random class DiceRoll: def __init__(self): self.history = [] def roll(self): total = random.randint(1,6) + random.randint(1,6) self.history.append(total) return total def __iter__(self): return iter(self.history)
After rolling the dice a few times, I attempted iterable unpacking, and it just worked:
test = DiceRoll() test.roll() # returned 5 test.roll() # returned 11 test.roll() # returned 10 test.roll() # returned 2 test.roll() # returned 8 first, *middle, last = test # unpacked into 5, [11, 10, 2], 8
Out of curiosity, I also attempted it on the alternate implementation using __getitem__()
:
import random class DiceRoll: def __init__(self): self.history = [] def roll(self): total = random.randint(1,6) + random.randint(1,6) self.history.append(total) return total def __getitem__(self, key): return self.history[key]
Perhaps unsurprisingly, it worked just as well:
test = DiceRoll() test.roll() # returned 6 test.roll() # returned 7 test.roll() # returned 4 test.roll() # returned 7 test.roll() # returned 6 first, *middle, last = test # stored 6, [7, 4, 7], and 6
Overall, I was extremely pleased with how robust the iterable and iterable unpacking features are in Python.
Up next, we’ll take a look at a brief history of the iterable unpacking feature.
Python Version History
It’s important to note that iterable unpacking has not been a permanent feature of Python, and it’s been modified over time. For example, the following lists some of the changes made to iterable unpacking since Python 3:
- Python 3.0: PEP 3132—Extended Iterable Unpacking
- Python 3.5: PEP 448—Additional Unpacking Generalizations
Unfortunately, prior to Python 3, iterable unpacking didn’t really exist to the extent it does now. Instead, folks were using a mix of indexing and slicing to manually unpack their iterables.
Unpacking More Concepts
Previously, we explored the idea of iterables, and today we looked at a feature of iterables called iterable unpacking. In the future, we’ll look to cover some of the related concepts that popped up today like slicing and indexing. Overall, I’m really enjoying watching this concept map grow! I hope you are too.
In the meantime, you’re welcome to browse some of these related articles:
- How to Swap Variables in Python: Temporary Variables and Iterable Unpacking
- How to Merge Two Dictionaries in Python: Comprehensions, Unpacking, and the Union Operator
- How to Get the Last Item of a List in Python: Iterable Unpacking and More
Similarly, you can start learning Python with any of the following resources (#ad):
- Effective Python: 90 Specific Ways to Write Better Python
- Python Tricks: A Buffet of Awesome Python Features
- Python Programming: An Introduction to Computer Science
Finally, you can support the site by heading over to my list of ways to grow the site. Otherwise, take care!
Recent Code Posts
Recently, I was thinking about how there are so many ways to approach software design. While some of these approaches have fancy names, I'm not sure if anyone has really thought about them...
Poetry 2.x was released in early 2025, and we just got around to migrating several of our open-source projects to the new major version. As a result, I wanted to share some of the lessons learned.