An iterator exposes one sequence of next() results and remains exhausted after its final value.
Python iterator reference: consume once or create a repeatable source
Operation contract
The fixture shows that list(iterator) consumes a one-use stream. Repeating list(iterator) is empty, while calling iter() on an owned tuple gives a new reader each time. A conversion to a tuple creates a reusable snapshot with its own storage cost. The choice belongs in an API contract: a database cursor should not be advertised as replayable unless the query is run again or rows are stored.
Failure and ownership boundary
An exhausted iterator is not an empty underlying collection. A generator may also hold files or other resources until it is closed. Python iterators: exhaustion and repeatable collection ownership, Python generator send and close: suspension retains state until cleanup and Python CSV ingestion: cap bytes, rows and fields before publication explain the resource side.
Working program
receipt_ids = (41, 42)
stream = iter(receipt_ids)
print("first:", list(stream))
print("second:", list(stream))
print("new reader:", list(iter(receipt_ids)))
print("snapshot:", tuple(receipt_ids))Output
first: [41, 42]
second: []
new reader: [41, 42]
snapshot: (41, 42)Costs and limits
Creating a tuple snapshot from n values costs O(n) time and references; creating an iterator over an existing tuple is bounded. Materializing list(iterator) costs O(r) for r remaining items.
Common Mistakes
- A consumed iterator is not reusable simply because its source still exists.
- Replaying a source can repeat I/O or see changed external state.
Connected lessons
Python iterators: exhaustion and repeatable collection ownership, Python generator send and close: suspension retains state until cleanup, Python CSV ingestion: cap bytes, rows and fields before publication.
