2012-06-12 13 views
7

presenté una solicitud de extracción con este código:corchetes no se requieren en las listas por comprensión cuando se utiliza en una función

my_sum = sum([x for x in range(10)]) 

Uno de los revisores sugirieron este lugar:

my_sum = sum(x for x in range(10)) 

(la diferencia es solo que faltan los corchetes cuadrados).

Me sorprendió que la segunda forma parezca ser idéntica. Pero cuando traté de usarlo en otros contextos donde funciona el primero, falla:

y = x for x in range(10) 
     ^SyntaxError !!! 

¿Las dos formas son idénticas? ¿Hay alguna razón importante de por qué los corchetes cuadrados no son necesarios en la función? ¿O es esto algo que tengo que saber?

+3

[Este enlace] (http://wiki.python.org/moin/Generators) podría ser útil también. – jadkik94

+0

También hay comprensión de diccionarios y conjuntos, en caso de que no haya oído hablar de ellos. – Amr

Respuesta

15

Esta es una expresión de generador. Para conseguir que funcione en el caso autónomo, utilice llaves:

y = (x for x in range(10)) 

e y se convierte en un generador. Puede iterar sobre generadores, por lo que funciona donde se espera una iterable, como la función sum.

Ejemplos de uso y las trampas:

>>> y = (x for x in range(10)) 
>>> y 
<generator object <genexpr> at 0x0000000001E15A20> 
>>> sum(y) 
45 

que tenga cuidado al mantenimiento de generadores alrededor, sólo se puede pasar por ellos una vez. Así que después de la anterior, si intenta utilizar sum de nuevo, esto sucederá:

>>> sum(y) 
0 

Así que si se pasa un generador, donde en realidad se espera una lista o un conjunto o algo similar, usted tiene que tener cuidado. Si la función o clase almacena el argumento e intenta iterar sobre él varias veces, se encontrará con problemas. Por ejemplo considere esto:

def foo(numbers): 
    s = sum(numbers) 
    p = reduce(lambda x,y: x*y, numbers, 1) 
    print "The sum is:", s, "and the product:", p 

se producirá un error si la mano es un generador:

>>> foo(x for x in range(1, 10)) 
The sum is: 45 and the product: 1 

Usted puede obtener una lista de los valores de un generador produce:

>>> y = (x for x in range(10)) 
>>> list(y) 
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9] 

Usted Puede usar esto para reparar el ejemplo anterior:

>>> foo(list(x for x in range(1, 10))) 
The sum is: 45 and the product: 362880 

Sin embargo, tenga en cuenta que si crea una lista a partir de un generador, deberá almacenar todos los valores. Esto podría usar mucha más memoria en situaciones donde tienes muchos artículos.

¿Por qué usar un generador en su situación?

El consumo de memoria mucho más baja es la razón por la cual es mejor que sum(generator expression)sum(list): La versión generador solamente tiene que almacenar un único valor, mientras que la lista variante tiene que almacenar N valores. Por lo tanto, siempre debe usar un generador donde no se arriesgue a los efectos secundarios.

+0

Además, las expresiones del generador a menudo usan menos memoria porque no se crea una lista intermedia. –

2

El primero es la lista comprehnsion Dónde segundo es la expresión generador de

(x for x in range(10)) 
    <generator object at 0x01C38580> 
    >>> a = (x for x in range(10)) 
    >>> sum(a) 
    45 
    >>> 

Uso aparato ortopédico para los generadores:

>>> y = (x for x in range(10)) 
>>> y 
<generator object at 0x01C3D2D8> 
>>> 
3

Ellos no son idénticos.

La primera forma,

[x for x in l] 

es una lista por comprensión. El otro es un generador de expresión escrita y de este modo:

(x for x in l) 

Devuelve un generador, no una lista.

Si la expresión del generador es el único argumento en una llamada a función, se pueden omitir sus paréntesis.

Ver PEP 289

0

Lea este PEP: 289

Por ejemplo, el siguiente código sumatoria va a construir una lista completa de las plazas en la memoria, iterar sobre esos valores, y, cuando la referencia ya no es necesario , eliminar la lista:

sum([x*x for x in range(10)]) 

memoria se conserva mediante el uso de un generador de expresión en su lugar:

sum(x*x for x in range(10)) 

Como los volúmenes de datos se hacen más grandes, las expresiones generadoras tienden a obtener mejores resultados, ya que no lo hacen de memoria caché de escape y permiten Python para reutilizar los objetos entre iteraciones.

producto Uso abrazadera un generador:

>>> y = (x for x in range(10)) 
>>> y 
<generator object <genexpr> at 0x00AC3AA8> 
Cuestiones relacionadas