Why Python’s zip Needs a Strict Mode: Understanding PEP 618
PEP 618 proposes adding an optional strict flag to Python's built‑in zip function to raise errors when iterables have mismatched lengths, preventing silent data loss and making debugging of common zip‑related bugs easier.
Abstract
This PEP proposes adding an optional boolean strict keyword argument to the built‑in zip class. When enabled, zip raises ValueError if any iterable is exhausted before the others.
Motivation
Many real‑world uses of zip assume the iterables have equal length. When they do not, the default behaviour silently drops mismatched items, leading to subtle bugs that are hard to detect.
Simple case example:
def apply_calculations(items):
transformed = transform(items)
for i, t in zip(items, transformed):
yield calculate(i, t)Other common patterns also suffer from silent truncation, such as unpacking with zip(*x) to create nested iterables or chunking data into equal‑sized groups.
A concrete bug appears in the standard library ast.literal_eval, where mismatched nodes are silently discarded.
Basic Principle
Some commenters label a boolean flag as a code‑smell, but Python already has several built‑in functions that accept boolean keyword arguments, for example:
compile(..., dont_inherit=True) open(..., closefd=False) print(..., flush=True) sorted(..., reverse=True)Adding strict follows this existing pattern.
Specification
When strict=True is passed, zip raises ValueError as soon as the iterator stops because of a length mismatch. The exception is raised at the point where the iterator would normally stop.
Backward Compatibility
The change is fully backward compatible; the existing behaviour corresponds to strict=False and remains unchanged.
Reference Implementation
A pure‑Python reference implementation of the proposed behaviour:
def zip(*iterables, strict=False):
if not iterables:
return
iterators = tuple(iter(iterable) for iterable in iterables)
try:
while True:
items = []
for iterator in iterators:
items.append(next(iterator))
yield tuple(items)
except StopIteration:
if not strict:
return
if items:
i = len(items)
plural = "" if i == 1 else "s 1-"
msg = f"zip() argument {i+1} is shorter than argument{plural}{i}"
raise ValueError(msg)
sentinel = object()
for i, iterator in enumerate(iterators[1:], 1):
if next(iterator, sentinel) is not sentinel:
plural = "" if i == 1 else "s 1-"
msg = f"zip() argument {i+1} is longer than argument{plural}{i}"
raise ValueError(msg)Rejected Opinions
(1) Add itertools.zip_strict
This was the most‑supported alternative on the python‑ideas mailing list and would be a viable fallback if the PEP were rejected.
(2) Follow Precedent
Since itertools.zip_longest already exists, adding a strict mode to the built‑in zip is a more natural solution than creating a new function.
(3) Usability
Enabling strict checking directly on zip lets users avoid writing cumbersome length‑checking logic.
(4) Maintenance Cost
Modifying the existing zip implementation is simpler and has negligible performance impact compared to adding a new function to itertools.
(5) Multiple Modes
Beyond the current "shortest" mode and the proposed "strict" mode, a "longest" mode would duplicate itertools.zip_longest and therefore is unnecessary.
(6) Adding Methods or Constructors to zip
Both zip.strict(...) as a classmethod and zip(...).strict() as an instance method have ambiguous semantics; the keyword argument approach avoids this confusion.
(7) Changing zip's Default Behaviour
The default behaviour is useful for many scenarios, such as handling infinite iterators, so it should remain unchanged.
(8) Callback for Remaining Objects
Using callbacks to handle leftover items would add unnecessary complexity for a problem that the strict flag solves cleanly.
(9) Raising AssertionError
PEP 618 argues that AssertionError is inappropriate; ValueError better matches the nature of the error.
(10) Adding Similar Feature to map
The PEP does not propose changes to map, but the discussion could inform future proposals.
(11) Do Nothing
Leaving zip unchanged would continue to allow silent data loss, which the strict mode aims to prevent.
PEP Metadata
PEP URL: https://www.python.org/dev/peps/pep-0618
Title: Add Optional Length‑Checking To zip
Author: Brandt Bucher
Created: 2020‑05‑01
Merged into version: 3.10
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
Python Crawling & Data Mining
Life's short, I code in Python. This channel shares Python web crawling, data mining, analysis, processing, visualization, automated testing, DevOps, big data, AI, cloud computing, machine learning tools, resources, news, technical articles, tutorial videos and learning materials. Join us!
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
