Python 的可迭代对象是否真的将所有值都存储在内存中?

Do Python's iterables really store all values in memory?

我正在阅读 e-satis 对 What does the "yield" keyword do in Python? 的回答。他说:

These iterables are handy because you can read them as much as you wish, but you store all the values in memory and this is not always what you want when you have a lot of values

我不太同意。但是我不能在那里发表评论。

那么问题来了:Python的迭代器真的把所有的值都存储在内存中了吗?

我以前也这么认为。但是自从昨天看到Python的详细文档后,我改变了看法。

>>> import sys
>>> def gen(): 
...   n = 0                                                                                          
...   while n < 10:                                                                                 
...     yield n                                                                                     
...     n += 1
...
>>> a = [0,1,2,3,4,5,6,7,8,9]
>>> b = range(10)  # b is a range object, which is a iterable
>>> c = gen(10)    # c is a iterator, which is a iterable too
>>> sys.getsizeof(a)
144
>>> sys.getsizeof(b)
48
>>> sys.getsizeof(c)
72
>>> B = list(b)                                                                                     
>>> C = list(c)                                                                                     
>>> a
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
>>> B
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
>>> C
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
>>> sys.getsizeof(B)                                                                                
200                                                                                                
>>> sys.getsizeof(C)                                                                           
160

我们误以为iterable将所有的值都存储在内存中,因为我们在使用iterable时习惯于获取所有的值。

我说得对吗?

您在引用该答案时删除了太多上下文。它是专门在像列表这样的可迭代对象的上下文中制作的。生成器和 yield 关键字在答案的后面分别介绍。

扩展您的报价:

Everything you can use "for... in..." on is an iterable; lists, strings, files...

These iterables are handy because you can read them as much as you wish, but you store all the values in memory and this is not always what you want when you have a lot of values.

列表和字符串的声明是正确的,它们存储在内存中。然而,它对于文件是不正确的,因为您可以遍历文件而不将其全部存储在内存中。

A python 可迭代对象可能会也可能不会将值存储在内存中。它一次通过一个值,在每一步它都可以从内存中提取值,从头开始创建它,或者从另一个来源(例如文件)读取它。

range() 是一个很好的例子:在 Python 2.x 中,它预先生成所有值并将它们存储在内存中,在 Python 3.x 中它根据需要生成它们。 return 都是可迭代对象。