Python: функция next () - PullRequest
       7

Python: функция next ()

42 голосов
/ 14 ноября 2009

Я изучаю Python из книги и наткнулся на этот пример:

M = [[1,2,3],
     [4,5,6],
     [7,8,9]]

G = (sum(row) for row in M) # create a generator of row sums
next(G) # Run the iteration protocol

Поскольку я абсолютный новичок, и автор не предоставил никакого объяснения примера или функции next (), я не понимаю, что делает код.

Ответы [ 3 ]

70 голосов
/ 14 ноября 2009

Выражение (sum(row) for row in M) создает так называемый генератор . Этот генератор оценит выражение (sum(row)) один раз для каждой строки в M. Однако генератор еще ничего не делает, мы только что настроили его.

Оператор next(G) на самом деле запускает генератор на M. Итак, если вы запустите next(G) один раз, вы получите сумму в первом ряду. Если вы запустите его снова, вы получите сумму во втором ряду и т. Д.

>>> M = [[1,2,3],
...      [4,5,6],
...      [7,8,9]]
>>> 
>>> G = (sum(row) for row in M) # create a generator of row sums
>>> next(G) # Run the iteration protocol
6
>>> next(G)
15
>>> next(G)
24

Смотри также:

10 голосов
/ 14 ноября 2009

Если вы зашли так далеко, то вы уже должны знать, как работает обычное утверждение for-in.

Следующее утверждение:

for row in M: print row

будет видеть M как последовательность из 3 строк (подпоследовательностей), состоящую из 3 элементов в каждой, и перебирать M, выводя каждую строку в матрице:

[1, 2, 3]
[4, 5, 6]
[7, 8, 9]

Ты знал это, хорошо ...

Вы можете видеть Генераторы как синтаксический сахар вокруг циклов for-in. Забудьте о вызове sum () и наберите что-то вроде этого в IDLE:

G = (row for row in M)
print G
for a in G: print a

Видите ли, генератор не может быть непосредственно представлен в виде текста, а не только как последовательность. Но вы можете перебирать Generator, как если бы это была последовательность.

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

Попробуйте следующее и посмотрите, что произойдет:

G = ("("+str(row[2])+";"+str(row[1])+";"+str(row[0])+")" for row in M)
G.next()
G.next()
G.next()
0 голосов
/ 15 октября 2018

Чтобы понять, как работает этот код, вам необходимо понять:

1) повторяемый объект?

2) итератор?

3) Протокол итерации

4) генератор?

5) Как работает генератор?

Позвольте мне дать представление о каждом из них:

Итерируемый : Итерируемым является любой объект в Python, для которого определен метод iter или getitem , который возвращает итератор или может принимать индексы. В основном объект по которому мы можем запустить цикл. например:

>>> for i in [1,2,3]:
print(i)

1 2 3

здесь у нас есть список как итеративный объект, элементы которого можно индексировать и извлекать с помощью индекса.

>>> for i in {x:1,y:2}:
print(x)

х у

здесь у нас есть словарь как итеративный объект, он перебирает свои ключи.

Итератор : Итератор - это любой объект в Python, для которого определен метод next (Python2) или next . Это оно. Это итератор.

Протокол итерации : встроенная функция iter принимает итеративный объект и возвращает итератор.

>>> x = iter([1, 2, 3])
>>> x
<listiterator object at 0x1004ca850>
>>> x.next()
1
>>> x.next()
2
>>> x.next()
3
>>> x.next()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
StopIteration

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

Например:

def yrange(n):
i = 0
while i < n:
    yield i
    i += 1

Каждый раз, когда выполняется оператор yield, функция генерирует новое значение.

>>> y = yrange(3)
>>> y
<generator object yrange at 0x401f30>
>>> y.next()
0
>>> y.next()
1
>>> y.next()
2
>>> y.next()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
StopIteration

Таким образом, генератор также является итератором.

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

Давайте разберемся с этим на примере:

>>> def foo():
     print "begin"
     for i in range(3):
         print "before yield", i
         yield i
         print "after yield", i
         print "end"

>>> f = foo()
>>> f.next()
begin
before yield 0
0
>>> f.next()
after yield 0
before yield 1
1
>>> f.next()
after yield 1
before yield 2
2
>>> f.next()
after yield 2
end
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
StopIteration

Теперь перейдем к вашей проблеме:

M = [[1,2,3],       #M is iterable object 
 [4,5,6],
 [7,8,9]]

G = (sum(row) for row in M) # creates a generator of row sums 
next(G) # Run the iteration protocol
...