The Iteration Protocol/shaare/sBPSEQ
The Iteration Protocol
We use for item in sequence: all the time. But how does Python get each item?
-
Iterable: An object that can be looped over. It's anything you can put on the right side of the
inkeyword in aforloop. Examples include lists, tuples, strings, dictionaries, sets, files, and range objects.- An object is considered iterable if it implements the
__iter__()special method. - The
__iter__()method returns an iterator.
- An object is considered iterable if it implements the
-
Iterator: An object that produces the next value in a sequence when asked. It "remembers" its position in the sequence.
- An object is an iterator if it implements the
__next__()special method. When there are no more items,__next__()raises theStopIterationexception. - Iterators normally also implement the
__iter__()method, which makes them iterables too.
- An object is an iterator if it implements the
Example: iterable returning an iterator
class CountTo:
def __init__(self, max_value):
self.max = max_value
def __iter__(self):
# Each new for-loop call
# gets its own iterator
return CountToIter(self.max)
class CountToIter:
def __init__(self, max_value):
self.max = max_value
self.curr = 1
def __iter__(self):
# Iterators are iterable
return self
def __next__(self):
if self.curr <= self.max:
val = self.curr
self.curr += 1
return val
else:
raise StopIteration
Supports nested loops: Decoupling iterables from iterators allow us to instantiate a single iterable and use it in nested loops without consuming the values from a single iterator.
my_foods = ["apple", "banana", "cherry"]
for food in my_foods:
for food2 in my_foods:
if food == food2:
print(f"Skipping duplicate food: {food}")
continue
print(f"Cooking {food} with {food2}")
class CountTo:
def __init__(self, max_value):
self.max = max_value
def __iter__(self):
return CountToIterator(self.max)
class CountToIterator:
def __init__(self, max_value):
self.max = max_value
self.current = 1
def __iter__(self):
return self
def __next__(self):
if self.current <= self.max:
val = self.current
self.current += 1
return val
else:
raise StopIteration
counter = CountTo(5)
for count in counter:
for count2 in counter:
print(f"Count: {count} and {count2}")
(97)