The __iter__ method in Python is a special method that is used to return an iterator for a container object. Basically, it makes an object iterable — the beholder of an iteration protocol, which allows Python to traverse through all the elements in a container object.
When a Python object is being iterated in a context such as a for loop, the interpreter calls the __iter__ method. This method must return an iterator object, which itself defines a __next__ method. The iterator object will use this __next__ method to get to the next value or the next object.
Consider an example where we have a custom list class:
class MyList:
def __init__(self, list):
self.list = list
def __iter__(self):
self.n = 0
return self
def __next__(self):
if self.n < len(self.list):
result = self.list[self.n]
self.n += 1
return result
else:
raise StopIteration
In the example above, any object instantiated from MyList becomes iterable. It can be looped over with a for loop, and each iteration will yield the next item in the list.
my_list = MyList([1, 2, 3, 4, 5])
for item in my_list:
print(item)
The output will be:
1
2
3
4
5
As we can see, implementing the __iter__ and __next__ methods can unleash the power of our own Python objects by making them iterable, just like the built-in Python types such as lists, tuples, strings, etc.
However, Python already provides generators and the 'yield' keyword which essentially helps us create iterables without having to write __iter__ or __next__ methods. They should be leveraged to keep your code more idiomatic and maintainable when creating a custom iterator object.
Remember, the key to Python's power is its simplicity and readability. The __iter__ method exemplifies these principles by providing a simple and straightforward way of creating iterable objects.