如何解决Python生成器generator
这是我在采访中遇到的一个问题(python 3.7):
def add(x,y):
return x+y
g = (x for x in range(4))
for n in [1,10]:
g = (add(n,i) for i in g)
list(g)
列表(g)打印什么?答案是
20,21,22,23
从输出中,我猜想发生了什么情况,即add函数循环了两次,而两次都是n = 10?有人可以向我解释逐步发生的情况吗?我感到很困惑。非常感谢。
解决方法
生成器表达式的“主体”无法捕获闭包中的值,因此n
只是一个自由变量,其值是在评估n
后分配给g
的值。 (迭代的表达式是,因此g
不是自由变量,而是当前分配给g
的可迭代对象。)
也就是说,在for
循环之后,您已经拥有
assert n == 10 # The last value assigned to n
# Pseudocode - every time n is used,it resolves to the *current*
# value of n,not the value n had when the generator expression was
# defined.
g = (add(10,i) for i in (add(10,i) for i in (x for x in range(4))))
# *not* (add(10,i) for i in (add(1,i) for i in (x for x in range(4))))
= (add(10,i) for i in (0,1,2,3)))
= (add(10,i) for i in (10,11,12,13))
= (10 + i for i in (10,13)
等等
list(g) == [20,21,22,23]
,
因为g
是生成器对象。
与立即计算的 listcomp 不同,它只是等待迭代的生成器 instance 。
>>> from inspect import getgeneratorstate
>>> g = (x for x in range(4))
>>> getgeneratorstate(g)
'GEN_CREATED'
>>> next(g)
0
>>> getgeneratorstate(g)
'GEN_SUSPENDED'
>>> list(g)
[1,3]
>>> getgeneratorstate(g)
'GEN_CLOSED'
但是,对第一个生成器(x for x in range(4))
的引用在生成器对象内部未更改。因为g
只是对内存中对象的引用。
名称仅仅是一个盒子上的便利贴。 -流利的Python。
因此,当我们传递g
时,仅传递引用对象的内存地址,而不传递g
本身。因此,在以下情况下:
>>> g = (x for x in range(4))
>>> g
<generator object <genexpr> at 0x036babbc>
>>> g = (add(n,i) for i in g)
生成器表达式g
中的 (add(n,i) for i in g)
只是将内存地址0x036babbc
传递给表达式,并且从该表达式创建的生成器 instance 会记住该地址,因此即使如果重新声明g
不会影响已经创建的生成器实例。
所以在续篇:
>>> g = (x for x in range(4))
>>> g
<generator object <genexpr> at 0x0452c22c> # 1
>>> g = (add(10,i) for i in g)
>>> g
<generator object <genexpr> at 0x044ee178> # 2
>>> g.gi_frame.f_locals['.0']
<generator object <genexpr> at 0x0452c22c> # 1 stored
>>> g = (add(10,i) for i in g)
>>> g
<generator object <genexpr> at 0x03bd88c8> # 3
>>> g.gi_frame.f_locals['.0']
<generator object <genexpr> at 0x044ee178> # 2 stored
如您所见,每个生成器表达式都会记住最后引用的生成器 instances ,因此它会不断嵌套。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。