Iterable


  • list, set, and dict are containers because they store all their elements in memory immediately. These containers are iterable, meaning we can loop through their elements with a for loop.

Iterator


  • When we wrap an iterable with iter(), we get back an iterator which is an object that remembers its position and produces one element at a time when we call next(). Once all elements are consumed, calling next() again raises a StopIteration exception.
  • An iterator object is not really a subclass of iterable, but rather it implements the iterator protocol (__iter__() and __next__()), which makes it both an iterator and an iterable, calling iter() on an iterator just returns itself. But but Iterator is a subclass of Iterable.

Generator


# Generator function
def count_up_to(n):
    for i in range(n):
        yield i
 
# Generator expression
(x*x for x in range(5))
  • A generator is a special kind of iterator that lazily produces values on demand instead of storing them all in memory.
  • We can create a generator in two ways: using a generator function that contains the yield keyword or a generator expression like (x*x for x in range(5)) as shown above

Super memory-efficient

They only compute each value when needed.

import sys
print(sys.getsizeof([x for x in range(1000000)]))   # large
print(sys.getsizeof((x for x in range(1000000))))   # tiny

Get Your Hands Dirty


# Let's import the core ABCs (Abstract Base Classes)
from collections.abc import Iterable, Iterator, Generator
 
# Example objects
lst = [1, 2, 3]
it = iter(lst)
gen = (x*x for x in range(3))
 
# ---- Check isinstance ----
print(isinstance(lst, Iterable))     # ✅ True, list is iterable
print(isinstance(lst, Iterator))     # ❌ False, list is not iterator
print(isinstance(it, Iterator))      # ✅ True
print(isinstance(gen, Iterator))     # ✅ True
print(isinstance(gen, Generator))    # ✅ True, generator is a kind of iterator
 
# ---- Check issubclass ----
print(issubclass(Iterator, Iterable))   # ✅ True, iterator implements iterable interface
print(issubclass(Generator, Iterator))  # ✅ True, generator is a subclass of iterator