zip()
Walk two or more iterables in parallel, one step at a time.
Common call
for a, b in zip(xs, ys):
Returns
iterator of tuples — length = shortest input
Replaces
manual index-based loops over parallel lists
Watch out
silently truncates to the shortest; strict=True raises
zip(*iterables, strictstrict — If True, raise ValueError when lengths differ. Added in Python 3.10.type: bool · default: False=False)
→ zip
Demo
Live evaluation
Try:
Inputs
alistfirst iterable
blistsecond iterable
strictint1 = strict, empty = off
Output
zip(['1', '2', '3'], ['a', 'b', 'c'])
[['1', 'a'], ['2', 'b'], ['3', 'c']]
zip stops at the shortest input by default — silently. Longer iterables lose their tail with no warning. Pass strict=True (Python 3.10+) to raise a ValueError instead. The demo materializes the iterator as a list of pairs.
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
| *iterables | iterable | yes | Any number of iterables. Each contributes one item per position. |
| strict | bool | no (False) | If True, raise ValueError when lengths differ. Added in Python 3.10. |
Return value
zip — An iterator of tuples — one tuple per position, containing the item from each iterable at that position. Lazy.
Common patterns
Parallel iteration
Same-position items from two lists, no indexing.
for name, age in zip(names, ages): print(name, age)
Dict from two lists
Keys from one, values from the other.
lookup = dict(zip(keys, values))
Transpose rows to columns
Star-unpack a list of rows — the classic matrix flip.
rows = [[1, 2, 3], [4, 5, 6]] cols = list(zip(*rows)) # [(1, 4), (2, 5), (3, 6)]
Examples
1. Basic pair
list(zip([1,2,3], ["a","b","c"]))
Returns
[(1, "a"), (2, "b"), (3, "c")]2. Uneven — truncates
list(zip([1,2], ["a","b","c"]))
Returns
[(1, "a"), (2, "b")]3. strict raises
list(zip([1,2], ["a","b","c"], strict=True))
Returns
ValueError: zip() argument 2 is longer than argument 14. Three iterables
list(zip([1,2],["a","b"],[True,False]))
Returns
[(1,"a",True), (2,"b",False)]Pitfalls
1. Silent truncation to shortest
The default drops the tail without warning — a classic source of bugs where you thought all items were processed.
Loses data
names = ["Ann", "Bob", "Cara"] ages = [30, 40] list(zip(names, ages))
[("Ann", 30), ("Bob", 40)] # Cara silently dropped
strict=True
list(zip(names, ages, strict=True))
ValueError: zip() argument 2 is shorter than argument 1
2. Iterator exhausts after one pass
zip returns an iterator, not a list.
Empty on reuse
z = zip(a, b) list(z) # populated list(z) # []
second call is empty
Materialize
pairs = list(zip(a, b))
reusable list
3. Passing one iterable pairs with nothing
zip of a single iterable gives 1-tuples, not the items themselves.
Odd shape
list(zip([1, 2, 3]))
[(1,), (2,), (3,)]
Just iterate
for x in [1, 2, 3]: ...
1, 2, 3
When to use
Use it
- Parallel iteration over aligned sequences
- Building a dict from parallel key/value lists
- Transposing rows to columns with zip(*rows)
- Aligned-length invariants → strict=True
Reach for something else
- Different-length inputs where truncation would hide bugs → strict=True or itertools.zip_longest
- Single iterable with counter → enumerate
- Cartesian product → itertools.product
Notes
Complexity
O(1) per step
Return
zip object (iterator), not list
CPython impl
Python/bltinmodule.c :: zip_next
Memory
O(1) — one item per iterable held at a time
Thread-safe
Only as safe as the underlying iterables
FAQ
zip in Python 2 built a list; itertools.izip was the lazy version. In Python 3 they merged — zip is lazy by default and izip is gone.
History
2.0
zip() introduced (returned a list).
3.0
zip() became lazy (returns an iterator).
3.10
strict keyword parameter added.