Вернитесь из итератора и затем бросьте StopIteration - PullRequest
6 голосов
/ 22 февраля 2012

Какой был бы хороший способ вернуть что-то из итератора в последний раз, когда он исчерпан. Я использую флаг, но это довольно некрасиво:

class Example():

    def __iter__(self):
        self.lst = [1,2,3]
        self.stop = False # <-- ugly            
        return self

    def next(self):
        if self.stop:  # <-- ugly
            raise StopIteration
        if len(self.lst) == 0:
            self.stop = True            
            return "one last time"
        return self.lst.pop()

Справочная информация: я извлекаю неизвестное количество строк из внешнего источника и отправляю их далее вызывающей стороне. Когда процесс закончен, я хочу выдать строку «x records обработано». У меня нет контроля над вызывающим кодом, поэтому это должно быть сделано внутри моего итератора.

Ответы [ 4 ]

6 голосов
/ 22 февраля 2012

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

class Example():

    def __iter__(self):
        lst = [1,2,3]
        for i in reversed(lst):
            yield i
        yield "one last time"
5 голосов
/ 22 февраля 2012

Возможно, вы можете использовать вместо этого функцию генератора:

def example():
    lst = [1, 2, 3]
    while lst:
        yield lst.pop()
    yield 'one last time'
1 голос
/ 22 февраля 2012

Не возвращайте еще одну вещь.Это плохая идея, потому что она не распространяется хорошо.Что делать, если вы хотите сделать сумму, а также считать?Или хэш, а также считать?Итератор - это объект с состоянием.Используйте это.

class Example( collections.Iterator ):
    def __iter__(self):
        self.lst = [1,2,3]
        self.count = 0       
        return self
    def next(self):
        if self.lst:
            self.count += 1
            return self.lst.pop()
        raise StopIteration()

Используйте это так.

my_iter= iter(Example())
for item in my_iterprin:
    print( item )

print( my_iter.count )
0 голосов
/ 22 февраля 2012

Вы могли бы сделать что-то вроде этого:

class Example():
    def __iter__(self):
        self.lst = [1, 2, 3]
        return self

    def next(self):
        try:
            return self.lst.pop()
        except IndexError:
            print "done iterating"
            raise StopIteration

>>> for i in Example():
...   print i
...
3
2
1
done iterating

В вашем фактическом коде вам, вероятно, потребуется изменить тип исключения, которое вы перехватываете, но этот формат все еще должен применяться.

...