Kevin Moon
Kevin Moon

Reputation: 21

why must one use __iter__() method in classes?

What exactly is the role of iter? Consider the following code block:

class Reverse:
    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]

omitting iter(self) and rewritting:

class Reverse2:
    def __init__(self,data):
        self.data = data
        self.index = len(data)
    def next(self):
        if self.index == 0:
            raise StopIteration
        self.index = self.index - 1
        return self.data[self.index]

Then:

x = [1,2,3]
y = Reverse(x)
z = Reverse2(x)
y.next()
>>> 3
y.next()
>>> 2
y.next()
>>> 1
z.next()
>>> 3
z.next()
>>> 2
z.next()
>>> 1

The classes behave the same way regardless of whether I include iter() or not, so why should i include it in the first place? I'm sorry if my question isn't clear--I simply don't know how to state it in a more clear way...

Upvotes: 0

Views: 96

Answers (2)

Daniel
Daniel

Reputation: 42758

The __iter__ method is always called, when an iterator is needed, e.g. by explicitly calling iter or in for-loops or when creating lists list(xy).

So you cannot use your second class Reverse2 in all these contexts.

>>> list(Reverse("abc"))
['c', 'b', 'a']
>>> list(Reverse2("abc"))
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: iteration over non-sequence

To answer the question in the comment: the __iter__-method must return any iterator or instance with a __next__-method. Only if your class is a iterator by itself, it should return self. An example of returning a generator as iterator:

class Reverse3:
    def __init__(self,data):
        self.data = data
    def __iter__(self):
        # returns an generator as iterator
        for idx in range(len(self.data)-1, -1, -1):
            yield self.data[idx]

Upvotes: 1

napuzba
napuzba

Reputation: 6288

The __iter__ return the iterator object which allows to convert the object to a container which can be iterated via for .. in ...

The iterator object is any object which define __next__ method which returns the next item if exists or raise StopIteration otherwise.

While __iter__ can return any such iterator object, It can return itself if it implement __next__ method.

For example:

class Reverse:
    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]

Now you can use in for loops:

for xx in Reverse(x):
    print xx

Upvotes: 0

Related Questions