Iterators & Generators
Iterables
Understanding iterables vs iterators — objects that can produce iterators, the iter() function, and building custom iterable collections.
Interview: Interviewers frequently ask the difference between iterables and iterators — a key Python concept.
An iterable is any object that can produce an iterator via iter(). Lists, strings, dicts, sets, and tuples are all iterables. The key difference: iterables have __iter__() (which returns a new iterator), while iterators also have __next__().
Iterable vs Iterator
- Iterable: Has
__iter__()— returns a fresh iterator each time. Can be iterated multiple times. - Iterator: Has both
__iter__()and__next__()— single-use, stateful. - A list is an iterable (not an iterator) —
iter([1,2,3])returns a new list_iterator each time - A generator is both an iterable and an iterator — it can only be consumed once
Common Iterables
- Sequences: list, tuple, str, range
- Collections: dict, set, frozenset
- Files: open file objects (iterate over lines)
- Custom: Any class that implements
__iter__()
Making Custom Iterables
Implement __iter__() to return a new iterator. Use __len__() and __getitem__() for additional support:
__iter__()should return a new iterator each time (so the iterable is reusable)__getitem__()with sequential indices also makes an object iterable (sequence protocol)__len__()enableslen()and helps with pre-allocation in some contexts
Interview Insight
The classic interview question: "Is a list an iterator?" Answer: No — a list is an iterable. iter(list) returns a list_iterator, which is the iterator. Lists can be iterated multiple times; iterators are consumed after one pass.
Use Cases
Custom collections — making domain objects iterable (playlists, inventories)
Data containers — wrapping lists/dicts with custom iteration behavior
API design — returning iterables from functions for flexibility
Testing — creating mock iterables for unit tests
Lazy data sources — iterables that fetch data on demand
Common Mistakes
Confusing iterables with iterators — iterables can be reused, iterators are single-pass
Returning self from __iter__ in a collection — makes it an iterator, not reusable
Not implementing __iter__ — relying only on __getitem__ is the older sequence protocol
Calling next() on an iterable directly — must call iter() first to get an iterator
Forgetting that generators are both iterables and iterators — they exhaust after one use