Python生成器对象:__sizeof __()

roo*_*oot 14 python generator internals

这可能是一个愚蠢的问题,但无论如何我都会问.我有一个生成器对象:

>>> def gen():
...     for i in range(10):
...         yield i
...         
>>> obj=gen()
Run Code Online (Sandbox Code Playgroud)

我可以测量它的大小:

>>> obj.__sizeof__()
24
Run Code Online (Sandbox Code Playgroud)

据说发电机被消耗掉了:

>>> for i in obj:
...     print i
...     
0
1
2
3
4
5
6
7
8
9
>>> obj.__sizeof__()
24
Run Code Online (Sandbox Code Playgroud)

......但obj.__sizeof__()仍然是一样的.

使用字符串它按预期工作:

>>> 'longstring'.__sizeof__()
34
>>> 'str'.__sizeof__()
27
Run Code Online (Sandbox Code Playgroud)

如果有人能够启发我,我将感激不尽.

Mar*_*ers 28

__sizeof__()不会做你认为它做的事情.该方法返回给定对象的内部大小(以字节为单位),而不是生成器要返回的项目数.

Python无法事先知道生成器的大小.以下面的无限生成器为例(例如,有更好的方法来创建计数器):

def count():
    count = 0
    while True:
        yield count
        count += 1
Run Code Online (Sandbox Code Playgroud)

那台发电机是无止境的 没有可分配的大小.然而,生成器对象本身占用内存:

>>> count.__sizeof__()
88
Run Code Online (Sandbox Code Playgroud)

你通常不会叫__sizeof__()你把它留给sys.getsizeof()函数,这也增加了垃圾收集器的开销.

如果您知道生成器将是有限的并且您必须知道它返回了多少项,请使用:

sum(1 for item in generator)
Run Code Online (Sandbox Code Playgroud)

但请注意,这会耗尽发电机.


ovg*_*vin 6

正如在其他答案中所说,__sizeof__返回一个不同的东西.

只有一些迭代器具有返回未返回元素数的方法.例如listiterator有一个相应的__length_hint__方法:

>>> L = [1,2,3,4,5]
>>> it = iter(L)
>>> it
<listiterator object at 0x00E65350>
>>> it.__length_hint__()
5
>>> help(it.__length_hint__)
Help on built-in function __length_hint__:

__length_hint__(...)
    Private method returning an estimate of len(list(it)).

>>> it.next()
1
>>> it.__length_hint__()
4
Run Code Online (Sandbox Code Playgroud)