Iterators Reference
Python's iterator protocol — __iter__, __next__, iter(), next(), and lazy evaluation.
Any object with __iter__() and __next__() methods is an iterator.
Used In: Custom data streams, database cursor wrappers, lazy file readers.
__iter__(self) -> self
__next__(self) -> value # raises StopIteration when doneclass Counter:
def __init__(self, start, stop):
self.current = start
self.stop = stop
def __iter__(self):
return self
def __next__(self):
if self.current >= self.stop:
raise StopIteration
val = self.current
self.current += 1
return val
for n in Counter(1, 4):
print(n)1
2
3Time Complexity: O(1) per step
Related Methods: iter(), next()
Convert an iterable to an iterator manually and advance it step by step.
Used In: Manual stream consumption, peeking at first element without loading all.
iter(iterable) / next(iterator, default=None)data = [10, 20, 30]
it = iter(data)
print(next(it))
print(next(it))
print(next(it, 'done')) # exhausted, returns default
print(next(it, 'done'))10
20
30
doneTime Complexity: O(1)
Common Mistakes: Calling iter() on an already-exhausted iterator does not reset it — you must create a new one.
Related Methods: __iter__, __next__
Distinguish between objects you can loop over (iterable) and stateful cursor objects (iterator).
Used In: Designing reusable vs single-use data streams.
iterable: has __iter__() only
iterator: has __iter__() and __next__()lst = [1, 2, 3]
it = iter(lst)
print(hasattr(lst, '__next__'))
print(hasattr(it, '__next__'))False
TrueTime Complexity: O(1)
Iterable can be looped multiple times (iter() creates a new cursor each call). Iterator is single-use — once exhausted, it cannot be reset.
Iterators compute values on demand — they don't load the entire sequence into memory.
Used In: Streaming ETL, reading large log files line by line.
for item in iterator:for i in range(10**9):
if i > 2:
break
print(i)0
1
2Time Complexity: O(1) memory
Related Methods: generator expressions