我试图在python中理解迭代器的概念,并在Python 3.5.2中尝试过这个。
x = list(range(1000)) # size of x is 9112 bytes
y = iter(x) # size of y is 56 bytes
del x
x = list(y) # size of x is again 9112 bytes
迭代器如何存储有关生成序列的信息?
它不包含所有元素,但即使在删除原始列表后,我们仍然能够从迭代器中重现原始列表?
如果它不包含所有元素,即使在删除x
之后它又知道哪个是下一个元素?
答案 0 :(得分:2)
因为迭代器中存储了足够的细节,所以它们能够生成序列的下一个元素而不需要那个" next元素"在记忆中。
要了解发生了什么,请创建我们自己的假迭代器
class Fakeiterator:
def __init__(self, range_list):
self.current = range_list[0]
self.high = range_list[-1]
def __iter__(self):
return self
def __next__(self):
if self.current > self.high:
raise StopIteration
else:
self.current += 1
return self.current - 1
在我们的__init__
方法中,我们已经存储了足够的细节(迭代器的起点和终点),使我们能够生成下一个元素而不必将其存储在内存中。就我们掌握这些信息而言,即使我们给出了包含2000个元素的列表,我们也只需知道起点和终点
在我们的__next__
方法中随时请求迭代器中的下一个元素,迭代器只是递增当前计数器并将其返回给我们。
让我们测试我们的迭代器:
>>> x = list(range(5))
>>> y = Fakeiterator(x)
>>> del x
>>> list(y)
[0, 1, 2, 3, 4]
>>>
list
构造函数重复调用__next__
,直到我们的迭代器引发StopIteration
,并且当前元素高于我们存储的最大元素时迭代器的创建。
但是在您的情况下,在列表中调用iter(x)
,会在内部返回 STORES x的list_iterator
对象。 x
仍然存储,但不再存储名称x
。
关于为什么getsizeof
返回较小的大小,其大小应该大于或等于原始列表的大小。来自文档
sys.getsizeof(object [,default])返回对象的大小 字节。对象可以是任何类型的对象。所有内置对象都将 返回正确的结果,但这不一定适用 第三方扩展,因为它是特定于实现的。
只有直接归属于对象的内存消耗才是 占,而不是它所指对象的记忆消耗。
如果给定,则在对象未提供时将返回default 意味着检索大小。否则会引发TypeError。
getsizeof()调用对象的 sizeof 方法并添加一个 如果对象由管理,则额外的垃圾收集器开销 垃圾收集器。
要证明让我们写一个快速的脚本
import sys
x = [1, 2, 3]
print(sys.getsizeof(x))
class storex():
def __init__(self, param):
self.param = param
y = storex(x)
print(sys.getsizeof(y))
print(y.param, sys.getsizeof(y.param))
运行脚本时。这是输出(在我的机器上,但它应该与你的相同)
88
56
[1, 2, 3] 88
即使列表[1, 2, 2]
长度为88个字节,当我们将其存储为storex
的属性时,它也不会自动使storex
变得比它大。因为storex
指的是它。它不是storex
直接
但是在打印y.param
的尺寸时,我们可以看到它仍然与原始[1, 2, 3]
列表的尺寸相同
同样del
不会从内存中删除对象,它只是取消绑定名称x
,因此x不会引用内存中的任何对象。 x的值只会在没有再次引用时被丢弃(垃圾收集)
以下是我的意思
>>> x = [1,2,3]
>>> class y: pass
...
>>> y.x = x
>>> id(x), id(y.x)
(140177507371016, 140177507371016)
>>> del x
>>> id(y.x)
140177507371016
>>> x
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
NameError: name 'x' is not defined
>>>
删除x
并不会自动删除[1,2,3]
指向的y.x
,即使他们的ID显示它们都指向内存中的同一对象。
答案 1 :(得分:1)
根据我的知识,del x不会记录内存中的值,因为你的y仍在引用它。它是一种指针。 x和y指的是相同的内存。
当你执行del x时,python将取消引用x并执行垃圾收集。
通过执行x = list(y),您将内存再次指向x。