список Python __iter__ метод вызывается в каждом цикле? - PullRequest
8 голосов
/ 30 марта 2011

Я пытаюсь создать класс, который наследуется от списка Python.Я хочу, чтобы элементы списка были инициализированы / завершены с каждым циклом списка.Я думал, что это можно сделать, переопределив метод __iter__ в списке python, но я не могу заставить его работать.Метод __iter__ вызывается только один раз?(см. ниже)

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

Вывод

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

Есть идеи, как мне добиться того, что я хочу сделать?

Ответы [ 5 ]

10 голосов
/ 30 марта 2011

Вы можете просто вернуть выражение генератора из __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 предлагает использовать генератор вместо выражения генератора, что облегчает отладку

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

в качестве альтернативы вы можете использовать imap здесь

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
3 голосов
/ 30 марта 2011

__iter__ возвращает объект итератора . Если вам нужно что-то делать на каждой итерации, вы должны реализовать свой собственный (он должен реализовать два метода, описанных в связанных документах).

2 голосов
/ 30 марта 2011

Метод класса Python __iter__() фактически возвращает объект итератора. См. Следующее для справки: http://docs.python.org/library/stdtypes.html#iterator-types

На объекте итератора метод next() будет вызываться на каждом шаге цикла. Вы можете написать собственный итератор, который будет возвращен вашим пользовательским списком.

0 голосов
/ 30 марта 2011

Я хочу, чтобы элементы списка инициализировались / завершались с каждым циклом списка

Список не имеет прямого контроля над этим.Несколько циклов могут обращаться к списку параллельно (например, во вложенных циклах).Каждый цикл контролируется итератором , и __iter__() должен возвращать итераторы каждый раз, когда он вызывается.Вы не можете возвращать один и тот же экземпляр итератора все время, потому что указанные параллельные циклы будут мешать друг другу.

Но внутри итератора вы можете создавать экземпляры элементов по мере необходимости.Завершение их внутри итератора вряд ли целесообразно, потому что, вернув элемент, вы теряете над ним контроль.Если вы доработаете его позднее, внешний код, который по-прежнему полагается на элемент, может завершиться ошибкой.Если вам нужно доработать свои предметы, возьмите на себя ответственность потребителя предметов.

0 голосов
/ 30 марта 2011

Я не совсем понимаю, что вы пытаетесь сделать, но то, что вам уже сказали, правда.next() - это метод, вызываемый на каждой итерации.

class MyList(list):
    def next(self):
        print "Do something"
        return list.next(self)

(я его не проверял)

...