2012-09-18 37 views
11

Esto puede ser una pregunta estúpida, pero lo preguntaré de todos modos. Tengo un generador objeto:Objetos de generador de Python: __sizeof __()

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

que puede medir su tamaño:

>>> obj.__sizeof__() 
24 

Se dice que los generadores consiguen consumidos:

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

... pero obj.__sizeof__() sigue siendo el mismo.

Con cuerdas que funciona como esperaba:

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

Estaría agradecido si alguien podría iluminar.

+1

Usted también puede estar interesado en [ 'sys.getsizeof()'] (http://docs.python.org/library/sys.html#sys.getsizeof) También considera la sobrecarga de gc (si eso te importa), y es un poco menos hackish. – mhawke

+0

@mhawke: ¡en realidad, el OP ni siquiera estaba interesado en '__sizeof__'! :) –

+0

@NedBatchelder: ¡sí, tienes razón! – mhawke

Respuesta

23

__sizeof__() no hace lo que usted piensa que hace. El método devuelve el tamaño interno en bytes para el objeto dado, no el número de elementos que un generador va a devolver.

Python no puede saber de antemano el tamaño de un generador. Tomemos como ejemplo el siguiente generador sin fin (ejemplo, hay mejores maneras de crear un contador):

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

que el generador es interminable; no hay tamaño asignable a eso. Sin embargo, el propio objeto generador de toma de memoria:

>>> count.__sizeof__() 
88 

uno no suele llamar __sizeof__() salid de aquella a la sys.getsizeof() function, que también añade la basura colector por encima.

Si conocer un generador va a ser finito y que tienen saber cuántos artículos que devuelve, utilice:

sum(1 for item in generator) 

pero tenga en cuenta que los escapes que el generador.

+1

De hecho, es posible tener infinitos generadores o generadores no deterministas –

+0

suena razonable :) gracias. – root

1

__sizeof__ devuelve el tamaño de la memoria de un objeto en bytes, no la longitud de un generador, que es imposible de determinar por adelantado ya que los generadores pueden crecer indefinidamente.

0

Si está seguro de que el generador que ha creado es "finito" (tiene un número contable de los elementos) y que no le importa esperar un tiempo usted puede usar lo siguiente para obtener lo que desea:

len(list(gen())) 

Como los otros carteles dicen __sizeof__() es una medida de cuánta memoria ocupa algo (un concepto de nivel mucho más bajo que probablemente raramente necesitará), no su longitud (que no es una característica de los generadores ya que no hay garantía tener una longitud contable).

6

Como dije en otras respuestas, __sizeof__ devuelve algo diferente.

Solo algunos iteradores tienen métodos que devuelven la cantidad de elementos no devueltos.Por ejemplo listiterator tiene un __length_hint__ método correspondiente:

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

gracias por el __length_hint__. también len (list (it)) consume un iterador pero __length_hint__ does not. – root

+0

@root Sí, 'list' lo consume, lo convierte en una lista (lo que requiere algo de memoria) y solo luego calcula la longitud de la lista creada. Mientras que 'length_hint' es un método especialmente implementado solo para el objeto del iterador de lista. – ovgolovin

Cuestiones relacionadas