从中创建迭代器对象后删除列表

时间:2016-10-01 14:47:12

标签: python iterator iterable

我试图在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之后它又知道哪个是下一个元素?

2 个答案:

答案 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。