我正在从一本书中学习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()函数的任何解释,我不明白代码在做什么。
答案 0 :(得分:69)
表达式(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
答案 1 :(得分:10)
如果你走得那么远,那么你应该已经知道了一个常见的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
你看,生成器不能直接表示为文本,而不能像序列那样直接表示。 但是,您可以像生成序列一样迭代生成器。
然后你会发现一些很大的不同,但基本原则是你可以使用生成器不仅仅返回序列中每个项的值,而是返回任何表达式的结果。在教程的示例中,表达式为sum(row)。
尝试以下操作,看看会发生什么:
G = ("("+str(row[2])+";"+str(row[1])+";"+str(row[0])+")" for row in M)
G.next()
G.next()
G.next()
答案 2 :(得分:0)
要了解此代码如何工作,您需要了解:
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)
x y
在这里,我们将字典作为可迭代的对象,它遍历其键。
迭代器:迭代器是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