首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >从列表创建迭代器对象后删除列表

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

Stack Overflow用户
提问于 2016-10-01 22:47:12
回答 2查看 233关注 0票数 4

我正在尝试理解python中迭代器的概念,并在Python 3.5.2中尝试了这一点。

代码语言:javascript
复制
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之后,它如何知道哪个是下一个元素

EN

回答 2

Stack Overflow用户

发布于 2016-10-01 23:10:44

因为迭代器中存储了足够的细节,使它们能够生成序列的下一个元素,而不需要内存中的“下一个元素”。

为了理解到底发生了什么,让我们创建我们自己的伪迭代器

代码语言:javascript
复制
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__方法中,每当我们请求迭代器中的下一个元素时,迭代器只是简单地递增当前计数器并将其返回给我们。

让我们测试一下我们的迭代器:

代码语言:javascript
复制
>>> x = list(range(5))
>>> y = Fakeiterator(x)
>>> del x
>>> list(y)
[0, 1, 2, 3, 4]
>>>

list构造函数反复调用__next__,直到我们的迭代器引发StopIteration,也就是当前元素高于我们在创建迭代器时存储的最大元素的时候。

但在您的示例中,在列表上调用iter(x)时,会返回一个list_iterator对象,在内部存储x。x仍然存储,但不再使用名称x

关于为什么getsizeof返回一个较小的大小,正如您所预期的那样,它应该大于或至少等于原始列表的大小。从文档中

sys.getsizeof( object,默认值)返回对象的字节大小。对象可以是任何类型的对象。所有内置对象都将返回正确的结果,但这不一定适用于第三方扩展,因为它是特定于实现的。

只考虑直接归因于对象的内存消耗,而不考虑它引用的对象的内存消耗。

如果给定,则当对象不提供检索大小的方法时,将返回默认值。否则将引发TypeError。

getsizeof()调用对象的_sizeof_方法,如果对象由垃圾收集器管理,则会增加额外的垃圾收集器开销。

为了演示这一点,让我们编写一个快速脚本

代码语言:javascript
复制
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))

当你运行脚本的时候。这是输出(在我的机器上,但它应该与您的相同)

代码语言:javascript
复制
88
56
[1, 2, 3] 88

即使列表[1, 2, 2]有88字节长,当我们将它存储为storex的属性时,它不会自动使storex变得比它大。因为storex引用了它。它不直接是storex的一部分

但在打印y.param的大小时,我们可以看到它与原始[1, 2, 3]列表的大小相同

此外,del不会从内存中删除对象,它只是解除名称x的绑定,这样x就不会引用内存中的任何对象。只有当不再引用x的值时,它才会被丢弃(垃圾回收

下面是我的意思的一个演示

代码语言:javascript
复制
>>> 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不会自动删除y.x所指向的[1,2,3],即使它们的id显示它们都指向内存中的同一对象。

票数 2
EN

Stack Overflow用户

发布于 2016-10-01 23:21:03

据我所知,del x不会del内存中的值,因为y还在引用它。它是一种指针。X和y指的是相同的内存。

当您执行del x时,python将取消对x的引用并执行垃圾收集。

而通过执行x=list(y),您再次将内存指向x。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/39807948

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档