2012-02-22 1 views
3

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

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

ответ

5

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

class Example(): 

    def __iter__(self): 
     lst = [1,2,3] 
     for i in reversed(lst): 
      yield i 
     yield "one last time" 
4

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

def example(): 
    lst = [1, 2, 3] 
    while lst: 
     yield lst.pop() 
    yield 'one last time' 
+2

Имейте в виду, что вы можете сделать метод '__iter__' объектом объекта самой функцией генератора, в тех случаях, когда вы не можете или не хотите напрямую использовать генератор. –

+0

Спасибо, «урожай» - это то, что я пропустил. – georg

0

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

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 

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

1

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

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

Я не могу этого сделать, потому что я не управляю вызывающим кодом (это приложение wsgi). – georg

+1

Я не управляю вызывающим кодом? Это редко бывает так. Позвоните им по телефону и поговорите с ними. –