Необходимо добавить элемент в начало итератора в Python

У меня программа такая:

a=reader.next()
if *some condition holds*:
    #Do some processing and continue the iteration
else:
    #Append the variable a back to the iterator
    #That is nullify the operation *a=reader.next()*

Как добавить элемент в начало итератора? (Или есть более простой способ сделать это?)

РЕДАКТИРОВАТЬ: ОК, позвольте мне сказать так. Мне нужен следующий элемент в итераторе, не удаляя его. Как мне это сделать>?


person Goutham    schedule 12.08.2009    source источник
comment
Вы либо делаете обертку точно так, как я объяснил в своем ответе, либо используйте itertools.tee, позвольте мне отредактировать свой ответ.   -  person Alex Martelli    schedule 12.08.2009


Ответы (4)


Итераторы Python, как таковые, имеют очень ограниченную функциональность - никакого «добавления» или чего-то подобного. Вам нужно будет обернуть общий итератор в оболочку, добавив эту функциональность. Например.:

class Wrapper(object):
  def __init__(self, it):
    self.it = it
    self.pushedback = []
  def __iter__(self):
    return self
  def next(self):
    if self.pushedback:
      return self.pushedback.pop()
    else:
      return self.it.next()
  def pushback(self, val):
    self.pushedback.append(val)

Это Python 2.5 (должен работать и в 2.6) - небольшие варианты рекомендуются для 2.6 и обязательны для 3.any (используйте next(self.it) вместо self.it.next() и определите __next__ вместо next).

Изменить: OP теперь говорит, что им нужно «заглядывать вперед, не потребляя». Обертывание по-прежнему является лучшим вариантом, но есть альтернатива:

import itertools
   ...
o, peek = itertools.tee(o)
if isneat(peek.next()): ...

это не продвигает o (не забудьте продвинуть его, если и когда вы решите, что ДЕЙСТВИТЕЛЬНО хотите ;-).

person Alex Martelli    schedule 12.08.2009
comment
Да, это сработает. Проблема только в том, что итератор довольно большой, но если другого выхода нет, то пока придется - person Goutham; 12.08.2009
comment
Не беспокойтесь - итератор хранится по ссылке в случае оболочки, и itertools.tee будет занимать дополнительное пространство O (K), где K - количество элементов, которые вам нужно заглянуть вперед. Так что большие итераторы - не проблема! - person Alex Martelli; 12.08.2009

Вы ищете itertools.chain:

import itertools

values = iter([1,2,3])  # the iterator
value = 0  # the value to prepend to the iterator

together = itertools.chain([value], values)  # there it is

list(together)
# -> [0, 1, 2, 3]
person kolypto    schedule 10.06.2019

По замыслу (в общих концепциях разработки) итераторы предназначены только для чтения, и любая попытка их изменить приведет к поломке.

В качестве альтернативы вы можете прочитать итератор в обратном направлении и добавить его в конец элемента hte (который на самом деле является началом :))?

person Russell    schedule 12.08.2009

Это не слишком близко к тому, о чем вы просили, но если у вас есть контроль над генератором и вам не нужно «подглядывать» до того, как значение будет сгенерировано (и возникнут какие-либо побочные эффекты), вы можете использовать _ 1_, чтобы указать генератору повторить последнее полученное значение:

>>> def a():
...     for x in (1,2,3):
...             rcvd = yield x
...             if rcvd is not None:
...                     yield x
... 
>>> gen = a()
>>> gen.send("just checking")
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: can't send non-None value to a just-started generator
>>> gen.next()
1
>>> gen.send("just checking")
1
>>> gen.next()
2
>>> gen.next()
3
>>> gen.next()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
StopIteration
person Mark Rushakoff    schedule 12.08.2009