0

I have been reading about Iterators in the python 2.7.x Documentation The given sample program in the link defines a __iter__ method to make the class "iterable".

However, i cannot find any use of __iter__ method defined in the class, i.e. to say- Even if i don't define __iter__ , i can still iterate upon the object of the class.

Code 1 # From the documentation

class Reverse:
    """Iterator for looping over a sequence backwards."""
    def __init__(self, data):
        self.data = data
        self.index = len(data)
    def __iter__(self):
        return self
    def next(self):
        if self.index == 0:
            raise StopIteration
        self.index = self.index - 1
        return self.data[self.index]

Code 2 # Except for defining the iter method it's the same.

class ReverseMod:
    """Iterator for looping over a sequence backwards."""
    def __init__(self, data):
        self.data = data
        self.index = len(data)
    # Missing __iter__()
    def next(self):
        if self.index == 0:
            raise StopIteration
        self.index = self.index - 1
        return self.data[self.index]

Output:

rev = Reverse('spam')
revMod = ReverseMod('spam')

rev.next() #m
rev.next() #a
rev.next() #p
...

revMod.next() #m
revMod.next() #a
revMod.next() #p
...

Objects from class Reverse and ReverseMod behave the same way. Only thing is when i do a iter(revMod) it says

TypeError: iteration over non-sequence

Why do i even need to concern myself about doing iter(revMod)? Why do i need to care defining __iter__ at all. Seems like i can get the functionalities of doing a .next() without defining __iter__ at all.

SeasonalShot
  • 2,357
  • 3
  • 31
  • 49
  • 1
    Have you tried `for x in rev:` and `for x in revMod:`? What happened? What can you conclude about `__iter__`? – Vincent Savard May 04 '16 at 17:18
  • `Reverse` is both an *iterator* and an *iterable*, `ReverseMod` is only the former – jonrsharpe May 04 '16 at 17:18
  • 2
    "Seems like i can get the functionalities of doing a .next() without defining `__iter__` at all." - yes, but that's not the point. Nobody wants to call `next` themselves; they want to perform `for` loops, or pass objects to `list`, or do other things that won't work with `ReverseMod`. – user2357112 May 04 '16 at 17:19
  • 1
    @jonrsharpe: Strictly speaking, an object that provides `next` but not `__iter__` doesn't meet Python's definition of an iterator, even though it provides similar functionality. For example, `isinstance(obj, collections.Iterator)` will report that such an object is not an iterator. – user2357112 May 04 '16 at 17:23
  • @VincentSavard I see, it cannot iterate over revMod. I can deduce this: Whenever we define an __iter__ within a class we make the class "iterable" meaning if we use the object in a loop, we can iterate the value(s) of that object within that loop. This is interesting, I still cannot make out an efficient use case to wrap my head around. – SeasonalShot May 04 '16 at 17:27
  • Note that with the 1st class if you move or copy `self.index = len(data)` into the `__iter__` you can do multiple `for` loops on the same `Reverse` instance. – PM 2Ring May 04 '16 at 17:37
  • 1
    @PM2Ring: Bad move. If you want something to support iterating over it repeatedly like that, it's much better to make `__iter__` create a separate object. Making an iterator's `__iter__` implicitly reset the iterator breaks a few corner cases with `next`-ing an iterator before you loop over it or continuing an iteration in a new loop, and it doesn't handle the common case of wanting to perform nested loops over a single object. – user2357112 May 04 '16 at 18:38
  • @user2357112 Ah, of course. I shall bear that in mind. – PM 2Ring May 05 '16 at 02:31

0 Answers0