Python生成器如何节省内存

5
我了解生成器的一般概念,即生成器返回一个可迭代对象,可以“保存状态”,并不会立即计算所有内容,而是在每次调用next时计算。那么这是如何实现的呢?例如:[x for x in range(10) if x%2==0](x for x in range(10) if x%2==0)。在列表推导式中,所有内容都会一次性被计算并存储在内存中。
在生成器中,不会产生整个列表,而是产生一个可迭代的生成器对象,它将在每次调用next时计算。但是这个生成器必须知道它的“边界”,对吧?如果生成器不在后台执行所有计算,它怎么知道从哪里继续执行呢?我认为它必须知道列表推导式中的每一步,最终,如果您一直遍历生成器,直到遇到StopIteration,那么您使用的大致上是相同的内存量。

您IP地址为143.198.54.68,由于运营成本限制,当前对于免费用户的使用频率限制为每个IP每72小时10次对话,如需解除限制,请点击左下角设置图标按钮(手机用户先点击左上角菜单按钮)。 - Martijn Pieters
range会返回一个列表(至少在Python 2.x中)...基本上完全抵消了生成器的任何好处... - Joran Beasley
2
@JoranBeasley:让我们慷慨地假设OP正在使用Python 3.x。 :-) - Martijn Pieters
好的,好的,说得对 :P - Joran Beasley
1个回答

1

但是这个生成器必须知道它的“边界”,对吗?

不需要!它只会继续执行,直到遇到 StopIteration。它一次只处理一个元素,然后将其丢弃。


我会检查上面提出的重复内容(之前我确实尝试过搜索),但这基本上是我不理解的地方。为了一次只处理一个项目,它必须知道在可迭代对象的顺序中它所处的位置,那么如果它丢弃每个先前的元素,它怎么知道呢?换句话说,如果它不保留累积计算(因此我认为在达到StopIteration时消除内存优势),它如何知道next已经被调用了“x”次,并且现在需要执行第三次计算,例如? - Solaxun
试着阅读一下这篇文章:http://www.jeffknupp.com/blog/2013/04/07/improve-your-python-yield-and-generators-explained/。生成器将在每次需要元素时简单地调用“next”,直到它们遇到“StopIteration”。它们不知道也无法知道“StopIteration”会发生在哪里,直到它们到达那里。 - Cory Kramer
1
对于未来的学习者...我发现SICP的第3.5节在这里对我帮助很大。它不会帮助你理解Python的特定实现,但是通用概念被解释得非常清楚。 - Solaxun

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接