Skip to content
AITroveRead. Build. Understand.
Make this comfortable

Python iterators: exhaustion and repeatable collection ownership

Last updated: 30 Sept 20264 min read
tutorial
IntermediateBy AITrove Editorial

An iterator returns itself from iter() and supplies successive values through next(), raising StopIteration when exhausted.

Download Python source kit

Operation contract

The receipt batch retains an immutable tuple snapshot. Each call to iter(batch) creates a fresh iterator, so separate readers can traverse the batch independently. Holding one iterator and converting it to a list twice instead consumes it once and then produces an empty result. An iterable collection and a one-use iterator are different public contracts.

Failure and ownership boundary

The tuple snapshot protects only the outer sequence. This fixture restricts receipt IDs to integers; accepting mutable receipt objects would retain their aliases. An iterator that reads a database cursor also owns a live I/O lifetime and cannot be treated like this in-memory batch. Python generators: lazy iteration does not make retained output free and Python context managers: clean up on success and failure explain that distinction.

Working program

python
class ReceiptBatch:
    def __init__(self, receipt_ids):
        candidate = tuple(receipt_ids)
        if any(type(identifier) is not int or identifier <= 0 for identifier in candidate):
            raise ValueError("positive receipt IDs required")
        self._receipt_ids = candidate
    def __iter__(self):
        return iter(self._receipt_ids)

batch = ReceiptBatch([41, 42])
reader = iter(batch)
print(list(reader))
print(list(reader))
print(list(batch))

Output

Output
[41, 42]
[]
[41, 42]

Costs and limits

Creating the tuple snapshot costs O(n) time and storage; creating an iterator is bounded. Materializing its remaining values into a list takes O(r) retained output.

Common Mistakes

  • Do not promise repeatable reads when returning the same iterator instance.
  • An outer tuple does not freeze mutable values stored inside it.

Connected lessons

Python generators: lazy iteration does not make retained output free, Python tuples: immutable containers can still contain mutable state, Python iterator interview: lazy calls, exhaustion and partial failure.

Check this related boundary

Python iterator reference: consume once or create a repeatable source.

Trace the related workflow

Python iter(callable, sentinel): stop a pull loop at a declared marker.

Trace the next boundary

Python zip(strict=True): reject a mismatched pair of input feeds, Python itertools.tee: a lagging reader retains buffered values.

python
iterator-protocol
Storage details