-1

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?

akBo
  • 29
  • 6
  • Because iterators should be idempotent. Consider `mylist = [1,2,3]`: You want: `iterator = iter(mylist); next(iterator); for x in iterator: print(x)` to print `2, 3`, not `1,2,3` because you already started iterating over it. – juanpa.arrivillaga Oct 23 '20 at 00:27
  • Note, `iter` resetting your iterator essentially makes it broken. Once `StopIteration` has been raised, trying to iterate over it again should *always raise `StopIteration`* (although note, file iterators actually break this because `.seek` resets it... but practicality beats purity I guess) – juanpa.arrivillaga Oct 23 '20 at 00:29

1 Answers1

2

__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.

tdelaney
  • 73,364
  • 6
  • 83
  • 116