Удаляет ли next () значения из генератора? - PullRequest
0 голосов
/ 10 июля 2020

Я написал генератор, который не делает ничего больше или меньше, чем сохраняет диапазон от 0 до 10:

result = (num for num in range(11))

Когда я хочу распечатать значения, я могу использовать next():

print(next(result))
[Out]: 0
print(next(result))
[Out]: 1
print(next(result))
[Out]: 2
print(next(result))
[Out]: 3
print(next(result))
[Out]: 4

Если я затем запустил for l oop на генераторе, он будет работать со значениями, которые я не назвал next() на:

for value in result:
    print(value)
[Out]: 5
6
7
8
9
10

Генератор отключен другие значения, воздействуя на них с помощью функции next()? Я попытался найти документацию по функциям next() и генераторов, но безуспешно.

Ответы [ 3 ]

3 голосов
/ 10 июля 2020

На самом деле это можно неявно вывести из next * документов и понимания iterator протокола / контракта :

следующий (iterator [, default])
Получить следующий элемент из итератора, вызвав его метод next (). Если задано значение по умолчанию, оно возвращается, если итератор исчерпан, в противном случае возникает StopIteration.

Да . Использование метода __next__ генератора извлекает и удаляет следующее значение из генератора.

2 голосов
/ 10 июля 2020

tldr; да

Итератор по сути является производителем значений, который выдает последовательные значения из связанного с ним итеративного объекта. Встроенная функция next() используется для получения следующего значения из итератора. Вот пример использования того же списка, что и выше:

>>> l = ['Sarah', 'Roark']
>>> itr = iter(l)
>>> itr
<list_iterator object at 0x100ba8950>
>>> next(itr)
'Sarah'
>>> next(itr)
'Roark'
>>> next(itr)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
StopIteration

В этом примере l - это повторяемый список, а itr - связанный итератор, полученный с помощью iter (). Каждый вызов next(itr) получает следующее значение из itr.

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

Если все значения от итератора уже были возвращены, возникает следующий вызов next() a StopIteration исключение. Любые дальнейшие попытки получить значения от итератора потерпят неудачу.

Мы можем получить значения от итератора только в одном направлении. go назад мы не можем. Функция prev() отсутствует. Но мы можем определить два независимых итератора для одного итерируемого объекта:

>>> l
['Sarah', 'Roark', 30]
>>> itr1 = iter(l)
>>> itr2 = iter(l)
>>> next(itr1)
'Sarah'
>>> next(itr1)
'Roark'
>>> next(itr1)
30
>>> next(itr2)
'Sarah'
1 голос
/ 10 июля 2020

Да, a for l oop in Python просто возвращает следующий элемент из итератора, так же, как и next().

https://docs.python.org/3/reference/compound_stmts.html#the -for-statement

Затем набор выполняется один раз для каждого элемента, предоставленного итератором, в порядке, возвращаемом итератором.

Итак, вы можете подумать о for l oop вот так:

for x in container:
    statement()

Как (почти) эквивалент while l oop:

iterator = iter(container)
while True:
    x = next(iterator)
    if x is None:
        break
    statement()

Если container уже является итератором, то iter(container) равно container.

Примечание: Технически, a для l oop выглядит примерно так:

iterator = iter(container)
while True:
    try:
        x = iterator.__next__()
    except StopIteration:
        break
    statement()
...