Last week I paired a list of 5 user IDs with a list of 4 email addresses using zip(). Python did not complain. The fifth user simply vanished from the output, and nobody noticed until a report came out short.
This is how zip() works by default: it stops at the shortest input and says nothing.
The problem in 5 lines
ids = [101, 102, 103, 104, 105]
emails = ["a@x.com", "b@x.com", "c@x.com", "d@x.com"]
pairs = list(zip(ids, emails))
print(len(pairs)) # 4, not 5
print(pairs[-1]) # (104, 'd@x.com') -- user 105 is gone, no error
No exception, no warning. If these lists come from a CSV, an API response or a database query, a missing row quietly becomes missing data.
Fix 1: strict=True (Python 3.10+)
Since Python 3.10, zip() accepts a strict argument. With it, a length mismatch raises an error instead of truncating:
pairs = list(zip(ids, emails, strict=True))
# ValueError: zip() argument 2 is shorter than argument 1
One keyword argument turns a silent data bug into a loud, easy-to-debug one. Use it whenever you expect the inputs to have the same length, which is most of the time.
Fix 2: keep everything with zip_longest
Sometimes the lists really can differ and you want to keep the extra items. Use itertools.zip_longest and choose a fill value:
from itertools import zip_longest
pairs = list(zip_longest(ids, emails, fillvalue=None))
print(pairs[-1]) # (105, None)
Now user 105 is still there, and you can handle the missing email on purpose.
Which one should you use?
| Situation | Use |
|---|---|
| Lists must match (columns of one table, keys and values) | zip(..., strict=True) |
| Lists may differ and you want every item | zip_longest(..., fillvalue=...) |
| You really want to stop at the shortest (e.g. pairing with an infinite counter) | plain zip()
|
Note on older Python: strict does not exist before 3.10, so on 3.9 or older, compare len() yourself before zipping.
Sources
- Python docs for
zip(): https://docs.python.org/3/library/functions.html#zip - PEP 618 (adds the
strictflag): https://peps.python.org/pep-0618/ -
itertools.zip_longest: https://docs.python.org/3/library/itertools.html#itertools.zip_longest
This article was written with AI assistance and checked by the author.
What is the sneakiest "no error, wrong result" bug you have hit in Python? I would like to collect a few more of these.
Top comments (0)