Как предотвратить истощение итератора в Python (3.x)?
=====================================================

 Если я создаю два списка и заархивирую их

 Затем я распечатываю z в два списка

 Затем содержимое l1 оказывается нормальным [(1,7), (2,8), (3,9)], но содержимое l2 просто [].

 Думаю, это общее поведение python по отношению к итерируемым. Но как начинающий программист, мигрирующий из семейства C, это не имеет смысла для меня. Почему он так себя ведет? И есть ли способ обойти эту проблему?

 Я имею в виду, да, в этом конкретном примере я могу просто скопировать l1 в l2, но в целом есть ли способ «сбросить» то, что Python использует для итерации «z» после того, как я повторю один раз?

can использование`itertools.tee` «копировать» итератор.

Это включает в себя кэширование значений, поэтому имеет смысл только, если вы повторяете оба итерации с примерно одинаковой скоростью. (Другими словами, не используйте его так, как я здесь!)

Другой подход - обойти функцию генератора и вызывать ее всякий раз, когда вы хотите выполнить итерацию.

Но теперь вы должны привязать аргументы к функции генератора при ее передаче. Ты можешь использовать`lambda` для этого, но многие люди находят`lambda` некрасиво. (Не я, хотя! YMMV.)

Я надеюсь, что само собой разумеется, что в большинстве случаев лучше просто составить список и скопировать его.

Кроме того, как более общий способ объяснить это поведение, рассмотрим это. Задача генератора - создать серию значений, сохраняя некоторое состояние между итерациями. Теперь иногда вместо простой итерации по генератору вы можете захотеть сделать что-то вроде этого:

Давайте скажем этот циклmay или жеmay not выпускной`z`, Теперь у нас есть генератор в неопределенном состоянии! Поэтому на данном этапе важно, чтобы поведение генератора ограничивалось четко определенным образом. Хотя мы не знаем, где находится генератор на его выходе, мы знаем, что a) все последующие обращения приведут кlater значения в серии, и b) после того, как она «пуста», мы получили все элементы в серии ровно один раз. Чем больше у нас возможностей манипулировать состоянием`z`чем сложнее рассуждать об этом, тем лучше, чтобы мы избегали ситуаций, нарушающих эти два обещания.

Конечно, как Джоэл Корнетт указывает ниже, этоis можно написать генератор, который принимает сообщения через`send` Способ; и было бы возможно написать генератор, который может быть сброшен с помощью`send`, Но учтите, что в этом случаеall we can do is send a message, Мы не можем напрямую манипулировать состоянием генератора, и поэтому все изменения в состоянии генератора четко определены (самим генератором - при условии, что он был написан правильно!).`send` действительно для реализации[сопрограммы](https://www.python.org/dev/peps/pep-0342/)поэтому я бы не использовал его для этой цели. Обычные генераторы почти никогда ничего не делают с отправленными им значениями - я думаю, по тем причинам, которые я привел выше.



`list()` один раз, и используйте его потом.

Бывает так, что`zip` возвращает**generator**, который является**iterator** что вы можете повторить только один раз.

Вы можете повторять список столько раз, сколько хотите.



 анация. Как программист, вы, вероятно, понимаете разницу между классами и экземплярами (т.е. объектами).`zip()` Говорят, чтоbuilt-in function (в официальном документе). На самом деле, этоbuilt-in **generator** function, Значит, это скорее класс. Вы даже можете попробовать в интерактивном режиме:

Классы являются типами. Из-за этого также должно быть ясно следующее:

Ваш`z` является экземпляром класса, и вы можете подумать о вызове`zip()` как насчет вызова конструктора класса:

`z` является итератором (объектом), который хранится внутри итераторов для`a` а также`b`, Из-за его общей реализации,`z` (или`zip` класс) не имеет смысла сбрасывать итераторы через`a` или же`b` или какие-то последовательности. Из-за этого нет способа сбросить`z`, Самый простой способ решить вашу конкретную проблему - скопировать список (как вы упомянули в вопросе и[Леннарт Регебро предлагает](https://stackoverflow.com/a/10868567/1346705)). Другим понятным способом является использование`zip(a, b)` дважды, таким образом построив два`z`-подобные итераторы, которые ведут себя с самого начала одинаково:

Тем не менее, это не может быть использовано в целомwith the identical result, Подумать о`a` или же`b` быть уникальными последовательностями, сгенерированными на основе некоторых текущих условий (скажем, температуры считываются с нескольких термометров)



Если вам нужны две копии списка, которые вы делаете, если вам нужно изменить их, то я предлагаю вам сделать список один раз, а затем скопировать его:



Генераторы генерируют свою продукциюonce, один за другим, по требованию, а затем выполняются, когда выход исчерпан.

Думайте о них, как о прочтении файла, после того как вы закончите, вам придется перезапустить компьютер, если вы хотите еще раз проверить данные.

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

Обновлено: исправлена терминология, временное отключение мозга ...