Почему zip () удаляет значения моего генератора?

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

In [1]: import itertools In [2]: gen = itertools.cycle((0,1,2)) In [3]: zip(gen, range(3)) Out[3]: [(0, 0), (1, 1), (2, 2)] In [4]: zip(gen, range(3)) Out[4]: [(1, 0), (2, 1), (0, 2)] 

По какой-либо причине метод next() gen называется одним дополнительным временем. Чтобы проиллюстрировать это, я использовал следующее:

  • Может ли библиотека запросов Python использоваться в Google App Engine?
  • В разных экземплярах класса используется одинаковое расположение памяти
  • быстро повторяя список кортежей
  • Подсчет гласных
  • Как объединить несколько исходных файлов Python в один файл?
  • Должен ли __init __ () вызывать __init __ () родительского класса?
  •  class loudCycle(itertools.cycle): def next(self): n = super(loudCycle, self).next() print n return n In [6]: gen = loudCycle((0,1,2)) In [7]: zip(gen, range(3)) 0 1 2 0 Out[7]: [(0, 0), (1, 1), (2, 2)] 

  • python os.environ, os.putenv, / usr / bin / env
  • Почему я должен ссылаться на «имена» и «привязку» в Python вместо «переменных» и «присваивания»?
  • Украшая методы класса python, как передать экземпляр в декоратор?
  • Разделить строку на обратную косую черту в python
  • кто может сказать мне, что можно назвать встроенными функциями в следующем коде
  • Объект Python .__ repr __ (self) должен быть выражением?
  • 2 Solutions collect form web for “Почему zip () удаляет значения моего генератора?”

    Это происходит потому, что zip оценивает итераторы слева направо , а это означает, что после трех шагов он вызывает next() в gen и только затем на iter(range(3)) (или что-то в этом роде) и сталкивается с StopIteration . Чтобы обойти это, используйте более короткий (конечный) итерабель как самый левый аргумент:

     In [8]: zip(range(3), gen) 0 1 2 Out[8]: [(0, 0), (1, 1), (2, 2)] 

    Ваш собственный ответ в точности правильный, и представляет собой очень хорошее решение – если один из аргументов zip всегда короче другого. Однако в ситуациях, когда вы не знаете, что будет короче, вы можете найти islice полезным. islice также обеспечивает удобное обходное решение, если вы хотите, чтобы первый элемент в ваших кортежах был из вашего генератора. В вашем случае вы можете сделать следующее:

     >>> import itertools >>> gen = itertools.cycle(('a', 'b', 'c')) >>> seq = range(3) >>> zip(itertools.islice(gen, len(seq)), seq) [('a', 0), ('b', 1), ('c', 2)] >>> zip(itertools.islice(gen, len(seq)), seq) [('a', 0), ('b', 1), ('c', 2)] 

    Ваш ответ, вероятно, лучше в этом случае – это, конечно, проще, но я думал, что добавлю это как дополнение.

    Python - лучший язык программирования в мире.