I'm relativley new to python (not coding) and I'm playing around with iterators in the language. When we build iterators I understand how they work and how to build a custom iterator, but I don't understand why we return self
in __iter__(self)
function.
Here's an example:
class Cube_Pow:
def __init__(self, max = 0):
self.max = max
def __iter__(self):
self.n = 0
return self
def __next__(self):
if self.n <= self.max:
cube = self.n ** 3
self.n += 1
return cube
else:
raise StopIteration
If I do the following:
cubes = Cube_Pow(10)
cube_iter = iter(cubes)
print(cube_iter) #output: <__main__.Cube_Pow object at 0x1084e8cd0>
My question is shouldn't the type be some iterator (for instance list has list_iterator
). Do have to extend some other class?
__iter__
makes something iterable. It returns an iterator but it is not the iterator itself. There are two approaches to iteration. An object can be its own iterator
>>> fileobj = open("test.txt")
>>> iter(fileobj) == fileobj
True
>>> print(type(fileobj), type(iter(fileobj)))
<class '_io.TextIOWrapper'> <class '_io.TextIOWrapper'>
Or it can return a different object to handle the iteration
>>> listobj = []
>>> iter(listobj) == listobj
False
>>> print(type(listobj), type(iter(listobj)))
<class 'list'> <class 'list_iterator'>
You return self
if you want all iterators of the object to iterate the same thing. That's what you want for a file which is doing sequential access under the covers. But for a list, you'd expect each iterator to start from the top again, so a new list_iterator
object is created each time to do just that.
An iterator usually returns self
so it is safe to call iter()
on it again (either directly or indirectly due to a for
loop or list comprehension or something).
Although there may be a specific reason in your case, an iterator resetting itself (self.n = 0
) is not what you want to do. Once you get an iterator, calling iter()
on it again shouldn't change it.