19

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

>>> def gen():
...     for i in range(10):
...         yield i
...         
>>> obj=gen()

我可以测量它的大小:

>>> obj.__sizeof__()
24

据说生成器被消耗:

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

...但obj.__sizeof__()保持不变。

使用字符串它可以按我的预期工作:

>>> 'longstring'.__sizeof__()
34
>>> 'str'.__sizeof__()
27

如果有人能启发我,我将不胜感激。

4

5 回答 5

38

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

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

def count():
    count = 0
    while True:
        yield count
        count += 1

那个发电机是无穷无尽的;没有可分配的大小。然而生成器对象本身需要内存:

>>> count.__sizeof__()
88

您通常不会__sizeof__()将其留给sys.getsizeof()function,这也会增加垃圾收集器的开销。

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

sum(1 for item in generator)

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

于 2012-09-18T13:17:47.047 回答
8

正如其他答案中所说,__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
于 2012-09-18T13:41:59.480 回答
1

__sizeof__返回对象的内存大小(以字节为单位),而不是生成器的长度,这是不可能预先确定的,因为生成器可以无限增长。

于 2012-09-18T13:19:06.200 回答
0

如果您确定您创建的生成器是“有限的”(具有可数数量的元素)并且您不介意等待一段时间,您可以使用以下内容来获得您想要的:

len(list(gen()))

正如其他海报所说__sizeof__(),是衡量某物占用多少内存(一个您可能很少需要的低级概念),而不是它的长度(这不是生成器的特性,因为不能保证它们具有可数长度) .

于 2012-09-18T13:21:40.190 回答
-1

@Martijn Pieters您也可以覆盖sizeof () 函数,我们可以实现我们在这里尝试做的事情。但它不适用于某些数据类型,如 int 或 float。

class GetLen():
    def __sizeof__(self, x):
        return len(x)

所以这里对于int或float,如果类型是int或float,我们也可以放置一些转义函数。

于 2018-10-08T06:53:55.577 回答