Сброс итератора, который является объектом карты? - PullRequest
0 голосов
/ 19 февраля 2020

Я учу Python самостоятельно.

Я встречал следующее

sol=map(pow,[1,2,3],[4,5,6])

sol - итератор.

Когда я последовательно запускаю next(sol), я буду перебирать элементы sol, пока не получу ошибку StopIteration.

Однако как я могу перезапустить итерацию?

Я пробовал iter_1=itertools.cycle(sol), но мне нужно перезапустить sol, запустив sol=map(pow,[1,2,3],[4,5,6]) и только потом iter_1=itertools.cycle(sol).

Есть ли другой способ?

Ответы [ 2 ]

2 голосов
/ 19 февраля 2020

Для достижения эффекта, который вы описали на OP, вы можете использовать itertools.cycle(). Примерно так:

Python 3.7.6 (default, Jan 30 2020, 09:44:41) 
[GCC 9.2.1 20190827 (Red Hat 9.2.1-1)] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> from itertools import cycle
>>> c = cycle(map(pow,[1,2,3],[4,5,6]))
>>> next(c)
1
>>> next(c)
32
>>> next(c)
729
>>> next(c)
1
>>> next(c)
32
>>> 

Но примите во внимание комментарии к ФП, прежде чем выбрать этот подход.

2 голосов
/ 19 февраля 2020

Итерация / генератор использует значения из него (бесконечные генераторы являются исключением), что означает, что они больше не будут доступны на будущих итерациях (как вы видели). Для типичного итератора / генератора в Python единственный верный способ «перезапустить» - это повторно инициализировать его.

>>> sol = map(pow, [1, 2, 3], [4, 5, 6])      
>>> list(sol)
[1, 32, 729]
>>> next(sol)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
StopIteration
>>> sol = map(pow, [1, 2, 3], [4, 5, 6])
>>> next(sol)
1

Существуют способы работы с итератором, чтобы сделать его многоразовым хотя, например, с itertools.tee (как упомянуто в одном из ответов на вопрос, связанный с @JanChristophTerasa), или для преобразования итератора в список, который сохранит свои данные.

itertools.tee

>>> from itertools import tee
>>> sol = map(pow, [1, 2, 3], [4, 5, 6])
>>> a, b = tee(sol, 2)  
>>> list(a)
[1, 32, 729]
>>> list(b)
[1, 32, 729]
>>> list(a)
[]

с tee, хотя и a, и b все равно будут итераторами, поэтому у вас возникнет та же проблема с ними.

Другой распространенный способ справиться с этим - list()

sol = list(map(pow, [1, 2, 3], [4, 5, 6]))
>>> sol
[1, 32, 729]
>>> sol
[1, 32, 729]

Теперь sol - это список значений вместо итератора, что означает, что вы можете повторять его столько раз, сколько хотите - значения останется там. Это означает , что означает, что вы не можете использовать next с ним (в смысле next(sol)), но вы можете получить итератор из вашего нового списка с помощью iter(sol), если вам нужен итератор специально .

Редактировать

Я видел itertools.cycle, упомянутый в комментариях, что также является допустимым вариантом, поэтому я подумал, что мог бы также добавить сюда некоторую информацию.

itertools.cycle - один из тех бесконечных генераторов, которые я упоминал в начале. Это все еще итератор , но таким образом, что у вас никогда не кончатся значения.

>>> from itertools import cycle
>>> sol = map(pow, [1, 2, 3], [4, 5, 6])
>>> infinite = cycle(sol)
>>> for _ in range(5):                        
...     print(next(infinite))
... 
1
32
729
1
32
>>> 

Несколько замечаний по этому поводу - после итерации infinite N раз будет располагаться после того, как из него было извлечено последнее значение. Повторная итерация позже возобновит с этой позиции, не с начала.

Кроме того, и это очень важно, не повторяется бесконечный генератор неограниченным образом, например, list(infinite) или for x in infinite:, иначе у вас будет плохое время.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...