1

What are the benefits of using the __iter__ function in a Python class?

In the code below I am just setting up two simple classes. The first class takes in a list as an argument, and I am able to loop over this list without using the __iter__ function. The second bit of code uses the __iter__ function to loop over a list.

What is the benefit of using __iter__ when there are already ways of looping over stuff in a class?

EG 1: no __iter__


class test_class:
    def __init__(self, list):
        self.container_list = list

    def print (self):
        a = self.container_list
        return a

test_list = test_class([1,2,3,4,5,6,7])

x = test_class.print(test_list)

for i in x:
    print (i)



EG 2: yes __iter__

class list_using_iter:
    def __init__(self):
        self.list = [1,2,3,4]
        self.index = -1

    def __iter__(self):
        return self

    def __next__(self):
        self.index += 1
        if self.index == len(self.list):
            raise StopIteration
        return self.list [self.index]

r = list_using_iter()
itr = iter(r)

print(next(itr))
print(next(itr))
print(next(itr))
print(next(itr))

print(next(itr)) # Raises the exception!
4
  • 1
    In the first case you are not iterating over the test_class object itself, you are iterating over what is returned by the test_class.print function (which is a list). Try something like: for i in test_class([1,2,3,4]): print(i) and see what happens. Commented Sep 25, 2017 at 17:21
  • __iter__ isn't for looping over stuff inside the class, it is for making the objects that are instances of the class iterable. Commented Sep 25, 2017 at 17:30
  • Note, also, you are simply re-implementing list_iterator in your list_using_iter class, which isn't very useful. I.e., it is equivalent to simply itr = iter([1,2,3,4]) Commented Sep 25, 2017 at 17:33
  • thanks for the comments. So the list in EG 1 is iterable anyway since it is a list. And I have missed the point of the iter function because it is used to iterate over instances of a class rather than attributes of a method that is inside a class ( which is what I have done in EG 1 with the list ) . What would it look like to loop over instances of a class? I know the init method constructs instances of a class. If I construct multiple instances of a class, then how are these instances stored and accessed by python? Commented Sep 25, 2017 at 17:45

2 Answers 2

1

Your first example is not iterable, but contains an attribute that is. Your second example is iterable, but you iterate simply by "following" another iterable. Here's an example of a iterable that does more work itself:

import itertools

class Fibs:
    def __init__(self, a, b):
        self.a = a
        self.b = b

    def __iter__(self):
        a = self.a
        b = self.b
        while True:
            yield a
            a, b = b, a + b

real_fibs = Fibs(0,1)

for i in itertools.islice(real_fibs, 10):
    print(i)

Fibs.__iter__ isn't simply regurgitating values obtained from some other value's __iter__ method; it is computing and yielding new values on demand.


Actually, the preceding is an example of a class that knows how to create its own iterator, rather than having each object be iterable. Here's a version that defines next itself.

class Fibs:
    def __init__(self, a, b):
        self.a = a
        self.b = b

    def __iter__(self):
        return self

    def __next__(self):
        rv = self.a
        self.a, self.b = self.b, self.a + self.b
        return rv
Sign up to request clarification or add additional context in comments.

1 Comment

thank you very much for the examples, they have made things so much clearer now :)
0

In both cases, the looping works because of __iter__. In your first example, your print function returns a loop. The implementation of the for keyword will call __iter__ (or the corresponding slot within the C implementation since the code involved is in the C interpreter) in order to loop over the list.

In your second example you could have written

for elt in r:
    print(elt)

which would have internally called __iter__ to implement the for loop.

In general you tend to use for rather than iter and next directly. The cases where you use iter and next directly are when you're producing a callback function that will produce an iterator or when you're defining one iterator in terms of another.

In terms of when should you write your own __iter__ or return some object that does its own iteration, that all depends on what functionality you want. For example, your first class is more powerful because two people can be iterating the list at the same time. In your second class, because you store the index in the class itself, only one person can successfully use the iterator at a time. However, if you had complex enough behavior, the second approach where you define your own __iter__ might make sense.

2 Comments

thanks for the answer Sam :) looks like the iter function is used automatically to do iteration with some python objects/commands. No need for calling it manually, unless I want to add iteration functionality to objects that do not have iteration builtin. Is this understanding correct?
It is. If this answers has answered your question, please accept it.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.