python list __iter__ method called on every loop?

scruffyDog picture scruffyDog · Mar 30, 2011 · Viewed 12.2k times · Source

I am trying to make a class which inherits from a python list. I want the elements of the list to be initialized/finalized with every loop of the list. I thought this could be done by overriding the __iter__ method of the python list but I can't seem to get it to work. The __iter__ method appears to called only once ? (see below)

class MyList(list):
    def __iter__(self):
        print 'do something'
        return list.__iter__(self)

my_list = MyList(range(10))
print my_list

for item in my_list:
    print item

Output

[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
do something
0
1
2
3
4
5
6
7
8
9

Any idea how I can achieve what I want to do?

Answer

John La Rooy picture John La Rooy · Mar 30, 2011

You can simply return a generator expression from __iter__()

class MyList(list):
    def __iter__(self):
        return (self.do_something(x) for x in list.__iter__(self))

    def do_something(self, x):
        print 'do something', x
        return x

my_list = MyList(range(10))
print my_list

for item in my_list:
    print item

ncoghlan suggests using a generator in place of the generator expression which makes for easier debugging

class MyList(list):

    def __iter__(self):
        for x in list.__iter__(self):
            yield self.do_something(x)

    def do_something(self, x):
        print 'do something', x
        return x

my_list = MyList(range(10))
print my_list

for item in my_list:
    print item

alternatively you could use imap here

from itertools import imap

class MyList(list):
    def __iter__(self):
        return imap(self.do_something, list.__iter__(self))

    def do_something(self, x):
        print 'do something', x
        return x


my_list = MyList(range(10))
print my_list

for item in my_list:
    print item