Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/350.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
python中生成器对象的大小_Python_Generator_Python Internals - Fatal编程技术网

python中生成器对象的大小

python中生成器对象的大小,python,generator,python-internals,Python,Generator,Python Internals,对于以下代码: import sys x=(i for i in range(1,11)) print x print 'Before starting iterating generator size is' ,sys.getsizeof(x) print 'For first time' for i in x: print i print 'For second time , does not print anything' for i in x: print

对于以下代码:

import sys
x=(i for i in range(1,11))
print x


print 'Before starting iterating generator size is' ,sys.getsizeof(x)

print 'For first time'
for i in x:
    print i

print 'For second time , does not print anything'    
for i in x:
    print i # does not print anything

print 'After iterating generator size is' ,sys.getsizeof(x)
输出为:


开始迭代之前,生成器大小为40
第一次
1.
2.
3.
4.
5.
6.
7.
8.
9
10
第二次
迭代后,生成器大小为40
生成器对象的大小最初是40,当我完成迭代时,它仍然是40。但是没有从第二个循环引用任何元素


为什么generator对象在创建时和完成对它的迭代时使用相同的内存?

generator
x
基本上是一个函数,每当调用它时,它都会提供
i
的下一个值。它不会预先计算所有值。它等待调用,然后计算并仅提供下一个值

因此,每次调用都将产生下一个值

为什么
x
的大小没有改变?这是因为
x
不是一个数字列表。在流程开始和结束时,它仍然是相同的函数

这是使用发电机的优点。您不必在一开始就将所有内容加载到内存中(这样可以节省内存),并且(如果操作正确的话)在实际需要之前不必计算任何内容(这样可以在不需要某些值的情况下节省计算时间)

要了解这一点:

x = (i for i in xrange(10**10))
for i in x:
    print i
    if i>10:
        break
print 'intermission'
for i in x:
    print i
    if i>20:
        break

(注意
xrange
,而不是
range
——使用
range
会导致提前计算)。想象一下从0到
10**10
实际生成整数需要多长时间,以及需要多少内存。比较这段代码的运行速度。

生成器在内存中占用的空间只是簿记信息。在其中,对框架对象的引用被保留(对运行的Python代码的管理,例如本地代码),无论它现在是否正在运行,对代码对象的引用也被保留。仅此而已:

>>> x=(i for i in range(1,11))
>>> dir(x)
['__class__', '__delattr__', '__doc__', '__format__', '__getattribute__', '__hash__', '__init__', '__iter__', '__name__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', 'close', 'gi_code', 'gi_frame', 'gi_running', 'next', 'send', 'throw']
>>> x.gi_frame
<frame object at 0x1053b4ad0>
>>> x.gi_running
0
>>> x.gi_code
<code object <genexpr> at 0x1051af5b0, file "<stdin>", line 1>
.0
对象是生成器在
for
循环中使用的
范围()
迭代器,
i
for
循环目标。
listiterator
是另一个iterable对象,它有一个对生成的list
range()
的私有引用,以及一个位置计数器,因此每次请求时它都可以生成下一个元素

不能查询生成器的元素大小;它们根据需要生成元素,但您无法先验地“知道”它们将生成多少,也无法知道它们在运行后生成了多少
sys.getsizeof()
当然不会告诉你;不管怎样,它都是一个测量内存占用的工具,如果你想知道总的内存占用,你必须递归地测量所有被引用的对象

您可以看到生成器已从机架完成运行;一旦完成,它将被清除:

>>> x.gi_frame
<frame object at 0x1053b4ad0>
>>> list(x)
[2, 3, 4, 5, 6, 7, 8, 9, 10]
>>> x.gi_frame is None
True
>>x.gi\u框架
>>>名单(十)
[2, 3, 4, 5, 6, 7, 8, 9, 10]
>>>x.gi_框架为无
真的
因此,最终,用于生成器的内存驻留在框架中的结构中(局部,可能是全局,这些名称空间中的每个对象可能再次引用其他对象),当生成器完成时,帧被清除,并且生成器
.gi_frame
指针被更改为指向
None
单例,如果引用计数下降到0,则帧被清除

所有这一切只适用于发电机,而不适用于一般的iterables;生成器是Python代码,因此可以对此进行深入反思

>>> x.gi_frame
<frame object at 0x1053b4ad0>
>>> list(x)
[2, 3, 4, 5, 6, 7, 8, 9, 10]
>>> x.gi_frame is None
True