Starred Assignment
Concepts covered: Unpacking
Reading a record by index means remembering that position 2 is the distance and position 3 is the splits. Unpacking gives each position a name instead. Write several names on the left of =, separated by commas, and Python assigns the tuple's items to them in order: first item to first name, second to second.
run = ("r_4821", "Lisbon", 5, (312, 298, 305, 291, 284))
run_id, city, km, splits = run
print(run_id)
print(city, km)
print(splits)Output:
r_4821 Lisbon 5 (312, 298, 305, 291, 284)
Plain unpacking needs an exact match: 4 names take 4 items. Give 3 names to a 7-item row and Python stops rather than guess which items you meant.
row = ("r_4821", "2026-03-14", 312, 298, 305, 291, 284)
run_id, date, first_split = row
print(run_id)The reverse mismatch, more names than items, raises ValueError: not enough values to unpack (expected 3, got 2). In both cases no name gets a value, and the program stops on that line.
A starred name takes what is left
Put * in front of 1 name and it becomes a collector. Python fills the plain names first, those before the star from the left end and those after it from the right end, then gives every remaining item to the starred name as a list. The 7-item row becomes readable in a single line: run_id, date, *splits = row gives 2 named fields and a list of however many splits the run recorded.
splits = (312, 298, 305, 291, 284)
first, *middle, last = splits
print(first)
print(middle)
print(last)
warmup, *rest = splits
print(warmup, rest)
*early, final = splits
print(early, final)312 [298, 305, 291] 284 312 [298, 305, 291, 284] [312, 298, 305, 291] 284
Three rules come out of that run. The starred name always holds a list, even when the source is a tuple. The star can sit first, last or between plain names. When nothing is left over, the starred name gets an empty list and no error is raised.
first, *middle, last = (7, 8)
print(first, middle, last)
head, *tail = ("only",)
print(head, tail)
run_id, *splits = ("r_9002", 301, 299)
print(splits)Output:
7 [] 8 only [] [301, 299]
| Target, for a 5-item tuple | Plain names get | Starred name gets |
|---|---|---|
| `a, b, c, d, e` | all 5 items | no starred name |
| `a, *rest` | `a` = 312 | `rest` = [298, 305, 291, 284] |
| `*rest, e` | `e` = 284 | `rest` = [312, 298, 305, 291] |
| `a, *rest, e` | `a` = 312, `e` = 284 | `rest` = [298, 305, 291] |
| `a, b, c, d, e, *rest` | all 5 items | `rest` = [] |
What does this program print?
a, *b, c, d = (10, 20, 30, 40, 50)
print(b, d)- (20, 30) 50
- [20, 30, 40] 50
- [30, 40] 50
- [20, 30] 50
Where a starred name still fails
A star relaxes the count, but every plain name still needs an item. a, b, *rest = (1,) stops with ValueError: not enough values to unpack (expected at least 2, got 1). The words at least in the message tell you a starred name was involved.
An assignment can hold 1 starred name at most. With 2, Python would have no way to decide how to divide the leftovers between them, so *a, *b = (1, 2, 3) is refused with a SyntaxError before any line of the program runs.
Skipping fields with an underscore
Often only a few fields matter. By convention the name _ marks a value you are deliberately not using, and *_ discards any number of them. Python treats _ like any other name; the convention tells the next reader that skipping it was on purpose.
row = ("r_4821", "2026-03-14", "Lisbon", 312, 298, 305, 291, 284)
run_id, _, city, *_ = row
print(run_id, city)
*_, last_split = row
print(last_split)Output:
r_4821 Lisbon 284
Unpacking in a for loop header
A for loop over a list of tuples can unpack each tuple right in its header. Every pass assigns the current tuple's items with the same rules: an exact count without a star, and at least the plain names with one. Here the uploads carry different numbers of splits.
runs = [
("ana", 312, 298, 305),
("ben", 280, 276),
("caro", 330),
]
for runner, first, *others in runs:
print(runner, first, others)Output:
ana 312 [298, 305] ben 280 [276] caro 330 []
About this lesson
This section is part of the Collections: Beginner lesson on DataDriven, the home of data engineering. Lessons cover SQL, Python, Spark, data modeling and pipeline architecture, and each section pairs its explanation with worked examples and practice you run as you go.