Python: next() 函数

Python: next() function

我正在从一本书中学习python,我遇到了这个例子:

1
2
3
4
5
6
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()函数的解释,所以我不理解代码在做什么。


表达式(sum(row) for row in M)创建了所谓的生成器。该生成器将对M中的每一行计算一次表达式(sum(row))。但是,发电机还没有做任何事情,我们只是设置了它。

声明next(G)实际运行M上的生成器。所以,如果你运行一次next(G),你会得到第一行的和。如果再运行一次,就会得到第二行的和,依此类推。

1
2
3
4
5
6
7
8
9
10
11
>>> 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

参见:

  • 发电机文件
  • 有关产量表达式的文档(包含有关生成器的一些信息)


如果你已经走了那么远,那么你应该已经知道了一个公共for语句是如何工作的。

以下声明:

1
for row in M: print row

将m视为3行(子序列)的序列,每行由3个项目组成,并迭代m,在矩阵上输出每行:

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

你知道的,嗯…

您可以将生成器看作是循环中的一些语法甜头。忘记sum()调用,然后在空闲时键入如下内容:

1
2
3
G = (row for row in M)
print G
for a in G: print a

可以看到,生成器不能直接表示为文本,而不仅仅是序列。但是,可以像序列一样迭代生成器。

然后您会发现一些很大的差异,但基本上您可以使用生成器,而不仅仅返回序列中每个项的值,而是返回任何表达式的结果。在本教程的示例中,表达式是sum(row)。

尝试以下操作,看看会发生什么:

1
2
3
4
G = ("("+str(row[2])+";"+str(row[1])+";"+str(row[0])+")" for row in M)
G.next()
G.next()
G.next()


要了解此代码如何工作,您需要了解:

1)不可识别对象?

2)迭代器?

3)迭代协议

4)发电机?

5)发电机如何工作?

让我来看看这些:

iterable:iterable是python中定义了iter或getitem方法的任何对象,该方法返回迭代器或可以获取索引。基本上是我们可以在其上运行循环的对象。如:

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

一二三

这里我们将列表作为一个不可重复的对象,它的项可以使用索引进行索引和检索。

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

XY

在这里,我们将字典作为iterable对象,循环其键。

迭代器:迭代器是python中定义了next(python2)或next方法的任何对象。就是这样。这是一个迭代器。

迭代协议:内置函数iter接受一个iterable对象并返回一个迭代器。

1
2
3
4
5
6
7
8
9
10
11
12
13
>>> 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

生成器:生成器是迭代器,但只能对它们进行一次迭代。这是因为它们不将所有值存储在内存中,而是动态生成值。

例如:

1
2
3
4
5
def yrange(n):
i = 0
while i < n:
    yield i
    i += 1

每次执行yield语句时,函数都会生成一个新值。

1
2
3
4
5
6
7
8
9
10
11
12
13
>>> 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()时,它都会从停止的位置恢复(它会记住所有的数据值以及上次执行的语句)。另一个关键特性是本地变量和执行状态在调用之间自动保存。

让我们用示例来理解这一点:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
>>> 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

现在我们来谈谈你的问题:

1
2
3
4
5
6
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