In the __iter__ scheme, classes implement user-defined iterables by simply implementing the iteration protocol.
The following code defines a user-defined iterable that generates squares on demand.
class Squares: def __init__(self, start, stop): # Save state when created self.value = start - 1 # w ww . j a va 2s . c o m self.stop = stop def __iter__(self): # Get iterator object on iter return self def __next__(self): # Return a square on each iteration if self.value == self.stop: # Also called by next built-in raise StopIteration self.value += 1 return self.value ** 2 for i in Squares(1, 5): # for calls iter, which calls __iter__ print(i, end=' ') # Each iteration calls __next__
Here, the iterator object returned by __iter__ is the instance self, because the __next__ method is part of this class itself.
Manual iterations work the same on user-defined iterables as they do on built-in types as well:
class Squares: def __init__(self, start, stop): # Save state when created self.value = start - 1 # w w w . j a va 2s. c om self.stop = stop def __iter__(self): # Get iterator object on iter return self def __next__(self): # Return a square on each iteration if self.value == self.stop: # Also called by next built-in raise StopIteration self.value += 1 return self.value ** 2 X = Squares(1, 5) # Iterate manually: what loops do I = iter(X) # iter calls __iter__ print( next(I) ) # next calls __next__ (in 3.X) print( next(I) ) print( next(I) ) print( next(I) ) # Can catch this in try statement X = Squares(1, 5) print( X[1] ) list(X)[1]