Пространство, которое занимает генератор, находится в памяти просто бухгалтерская информация. В нем хранится ссылка на объект фрейма (администрирование для запуска кода Python, например, locals), или оно работает прямо сейчас, и ссылка на объект кода сохраняется. Ничего больше:
>>> 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>
Это всего 3 ссылки, плюс информация обычного Python типа объекта (думает, что подсчет ссылок) и список слабых ссылок; так что это около 4 указателей, целое число и структура, которые на вашей системе занимают 40 байт (в моей системе 64-разрядная ОС X составляет 80 байт). sys.getsizeof()
сообщает о размере только, что структура реализована в C, и она не рекурсирует по указателям.
Таким образом, этот объем памяти не изменится, когда вы пропустите генератор. Связанный кадр может изменяться в зависимости от того, сколько памяти используется (если выражение генератора ссылается на большие объекты на один конец или другой), но вы не увидите этого с результатом sys.getsizeof()
на объекте генератора; смотреть на каркасных местными жителями вместо:
>>> next(x)
1
>>> x.gi_frame.f_locals
{'i': 1, '.0': <listiterator object at 0x105339dd0>}
Объект .0
является range()
итератора, что генератор использует в цикле for
, i
является целью по for
петли.listiterator
- это еще один итерируемый объект, который имеет личную ссылку на список 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
Таким образом, в конце концов, память, используемая для генератора находится в структурах в кадре (местные жители, и, возможно, глобал, с каждым объектом в этих пространствах имен, возможно, ссылки на других объекты снова), и когда генератор будет выполнен, рама будет очищена, а указатель генератора .gi_frame
будет изменен, чтобы указать на однотонный сигнал None
, оставляя рамку очищенной, если отсчет отсчета снизился до 0.
Все это только относится к генераторам, а не к итерам в целом; генераторы - это код Python и, таким образом, могут быть глубоко изучены.