zip()

Walk two or more iterables in parallel, one step at a time.

Built-in functionPython 2.0+Live demo
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, strictstrictIf 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

NameTypeRequiredDescription
*iterablesiterableyesAny number of iterables. Each contributes one item per position.
strictboolno (False)If True, raise ValueError when lengths differ. Added in Python 3.10.

Return value

zipAn 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 1
4. 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.