What is an iterable?

An iterable is anything you can loop over. It has an __iter__() method that returns an iterator.

# Common iterables:
my_list = [1, 2, 3]  # Iterable
my_string = "hello"  # Iterable
my_dict = {'a': 1}   # Iterable

# All can be used in for loops:
for item in my_list:
    print(item)

What is an iterator?

An iterator is an object that produces values one at a time. It has __next__() method.

my_list = [1, 2, 3]
iterator = iter(my_list)  # Get iterator

print(next(iterator))  # 1
print(next(iterator))  # 2
print(next(iterator))  # 3
# print(next(iterator))  # StopIteration error

How for loops work

A for loop automatically gets an iterator and calls next() until StopIteration:

# This:
for item in [1, 2, 3]:
    print(item)

# Is equivalent to:
iterator = iter([1, 2, 3])
while True:
    try:
        item = next(iterator)
        print(item)
    except StopIteration:
        break

Creating your own iterator

class CountDown:
    def __init__(self, start):
        self.current = start
    
    def __iter__(self):
        return self
    
    def __next__(self):
        if self.current <= 0:
            raise StopIteration
        self.current -= 1
        return self.current + 1

# Use it:
for num in CountDown(5):
    print(num)  # 5, 4, 3, 2, 1

Key points

  • Iterable: Can be looped over (has __iter__())
  • Iterator: Produces values (has __next__())
  • All iterators are iterables, but not all iterables are iterators
  • Iterators are consumed (can only iterate once)