2016-10-01 74 views
3

我想了解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

简短的回答....因为它有足够的信息封装在它里面重新创建原始序列...当你消耗它 – danidee

回答

2

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

明白什么是对,让我们创造我们自己的假迭代

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),返回list_iterator对象STORES X内部。 x仍然存储,但不是名称x了。

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

sys.getsizeof(object [,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表明他们都指向内存中的同一个对象。

+0

感谢和抱歉,这个迟到的答复。但是我仍然有一些疑问: – racerX

+0

a)我刚刚发布范围作为示例。在这种情况下,使用低值和高值以及步骤存储信息非常容易。但是,如果序列是随机的呢? – racerX

+0

(我很抱歉,但我不知道为什么我无法编辑我自己的评论,并按Enter继续发布每一句作为新的评论。)b)如果我删除x,那么迭代器仍然依赖于记忆权利,否则它将无法产生价值。因此,就内存而言,它仅在我们使用内置的迭代器(如Python 3.5中的范围)时才有用。在我的例子中,Python无法在内部告诉它它是一个范围,所以它需要将整个列表存储在内存中,因此除了理解概念外,没有理由去做原来的文章。 – racerX

1

根据我所知,del x不会删除内存中的值,因为你仍然在引用它。这是一种指针。 x和y指的是相同的内存。

当你做del x时,python会解引用x并做垃圾回收。

虽然通过x = list(y),您将内存再次指向x。