Interview frequency: …
Short answer
An iterable is an object you can get an iterator from through iter() (such as a list); an iterator remembers its position, returns the next item through next(), and is consumed only once.
Explanation
You can loop over a list many times because each loop creates a fresh iterator. A generator or a file object, however, is an iterator: after it is consumed, a second loop yields nothing. That is why passing a generator to two functions leaves the second one with empty data. If you need more than one pass, convert the result to a list or recreate the generator.
Code example
numbers = (n * n for n in range(3)) # generator = iterator
print(sum(numbers)) # 5
print(sum(numbers)) # 0 — Already consumed
items = [1, 2, 3] # iterable
it = iter(items)
print(next(it), next(it)) # 1 2Common mistakes
- Reusing a generator after it was consumed and expecting the same data.
- Converting every iterator to a list too early, which cancels the benefit of lazy processing.
Follow-up questions
- Which protocol makes an object usable in a for loop?
- How do generators and yield reduce memory usage?