2012-09-18 19 views
11

To może być głupie pytanie, ale mimo to zapytam. Mam obiekt generatora:Python generator objects: __sizeof __()

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

mogę zmierzyć jego wielkość:

>>> obj.__sizeof__() 
24 

Mówi się, że generatory uzyskać spożywane:

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

... ale obj.__sizeof__() pozostaje taka sama.

ze strunami to działa jak się spodziewałem:

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

Byłbym wdzięczny jeśli ktoś mógłby mnie oświecić.

+1

Możesz być także zainteresowany [ 'sys.getsizeof()'] (http://docs.python.org/library/sys.html#sys.getsizeof). Rozważa także koszty ogólne GC (jeśli to ma znaczenie dla ciebie) i jest trochę mniej hackish. – mhawke

+0

@mhawke: faktycznie OP nie był nawet zainteresowany '__sizeof__'! :) –

+0

@NedBatchelder: tak, masz rację! – mhawke

Odpowiedz

23

__sizeof__() nie robi tego, co myślisz. Metoda zwraca rozmiar wewnętrzny w bajtach dla danego obiektu, a nie liczbę elementów, które generator ma zamiar zwrócić.

Python nie może wcześniej wiedzieć, jaki jest rozmiar generatora. Weźmy na przykład następujące niekończące generator (przykład, istnieją lepsze sposoby tworzenia licznika):

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

że generator jest nieskończona; nie ma na to żadnego rozmiaru. Jednak sam obiekt generator trwa pamięć:

>>> count.__sizeof__() 
88 

Nie normalnie zadzwonić __sizeof__() zostawisz że do sys.getsizeof() function, który dodaje również Garbage Collector napowietrznych.

Jeśli wiesz generator będzie skończony i masz wiedzieć, ile przedmiotów powraca, zastosowanie:

sum(1 for item in generator) 

jednak pamiętać, że wyczerpuje generatora.

+1

Rzeczywiście można mieć nieskończone generatory lub niedeterministyczne generatory dźwięków –

+0

brzmi rozsądnie :) dziękuję. – root

1

__sizeof__ zwraca rozmiar pamięci obiektu w bajtach, a nie długość generatora, która jest niemożliwa do określenia z przodu, ponieważ generatory mogą rosnąć w nieskończoność.

0

Jeżeli jesteś pewien, że masz stworzył generator jest „skończony” (ma numer przeliczalny elementów) i nie przeszkadza czeka jakiś czas można użyć następujących czynności, aby uzyskać to, czego chcą:

len(list(gen())) 

Tak jak inne plakaty mówiły, że __sizeof__() to miara ilości zajmowanej przez nie pamięci (znacznie niższa koncepcja, której prawdopodobnie rzadko będziesz potrzebować), a nie jej długości (co nie jest cechą generatorów, ponieważ nie ma żadnej gwarancji, że mieć policzalną długość).

6

Jak powiedziano w innych odpowiedziach, __sizeof__ zwraca inną rzecz.

Tylko niektóre iteratory mają metody zwracające liczbę niezwróconych elementów.Na przykład listiterator posiada odpowiedni __length_hint__ metody:

>>> 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 
+0

dzięki za __length_hint__. również len (list (it)) zużywa iterator, ale __length_hint__ nie. – root

+0

@root Tak, 'list' zużywa ją, konwertuje na listę (która zajmuje trochę pamięci) i dopiero potem oblicza długość utworzonej listy. Natomiast 'length_hint' jest specjalnie zaimplementowaną metodą tylko dla obiektu iteratora list. – ovgolovin