Объекты генератора Python: __sizeof __()
Это может быть глупый вопрос, но я все равно спрошу. У меня есть объект-генератор:
>>> 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
Я был бы признателен, если бы кто-нибудь мог просветить меня.
Ответы
Ответ 1
__sizeof__()
не делает то, что вы думаете. Метод возвращает внутренний размер в байтах для данного объекта, а не количество элементов, которые будет возвращать генератор.
Python не может заранее знать размер генератора. Возьмем, к примеру, следующий бесконечный генератор (например, есть лучшие способы создания счетчика):
def count():
count = 0
while True:
yield count
count += 1
Этот генератор бесконечен; для него нет назначаемого размера. Однако сам объект-генератор принимает память:
>>> count.__sizeof__()
88
Обычно вы не вызываете __sizeof__()
, вы оставляете это для функции sys.getsizeof()
, которая также добавляет служебные данные сборщика мусора.
Если вы знаете, что генератор будет конечным, и вы должны знать, сколько элементов он возвращает, используйте:
sum(1 for item in generator)
но обратите внимание, что это истощает генератор.
Ответ 2
Как сказано в других ответах, __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
Ответ 3
__sizeof__
возвращает размер памяти объекта в байтах, а не длину генератора, который невозможно определить спереди, так как генераторы могут расти неограниченно.
Ответ 4
Если вы уверены, что созданный генератор "конечен" (имеет счетное количество элементов), и вы не возражаете ждать, пока вы сможете использовать следующее, чтобы получить то, что вы хотите:
len(list(gen()))
Как утверждают другие плакаты __sizeof__()
, это мера того, сколько памяти что-то занимает (концепция гораздо более низкого уровня, которая вам, вероятно, понадобится), а не ее длина (что не является особенностью генераторов, поскольку нет гарантии они имеют счетную длину).