2009-03-15 12 views
10

que ver este tipo de cosas a veces:Caso de uso para comprensiones de listas anidadas/múltiples o expresiones de generador. ¿Cuándo es más elegante?

(k for k in (j for j in (i for i in xrange(10)))) 

Ahora bien, esto realmente se inclina mi cerebro, y yo preferiría que no se presentó de esta manera.

¿Hay algún caso de uso, o ejemplos de haber usado estas expresiones anidadas donde era más elegante y más legible que si hubiera sido un ciclo anidado?

Edit: Gracias por los ejemplos de formas de simplificar esto. No es realmente lo que pedí, me preguntaba si hubo momentos en que fue elegante.

+1

"Sometimes"? De Verdad? ¿Qué estás leyendo? –

+1

Fragmentos de código, proyectos de código abierto. Eso sería revisado por código de todo lo que alguna vez había logrado. –

+0

¿Dónde has visto tal cosa? ¿Puedes proporcionar una URL específica? –

Respuesta

18

Compruebe PEP 202 que fue donde se introdujo la sintaxis de comprensiones de la lista en el idioma.

Para la comprensión de su ejemplo, no hay una regla simple de sí mismo Guido:

  • La forma [... x ... para cl ...] nidos, con el último índice que varía de más rápido , como anidados para bucles.

También desde PEP 202, que sirve para responder a su pregunta:

 
Rationale 
    List comprehensions provide a more concise way to create lists in 
    situations where map() and filter() and/or nested loops would 
    currently be used. 

Si tuviera una situación como esa, se puede encontrar que sea más elegante. En mi humilde opinión, sin embargo, las comprensiones de listas anidadas múltiples pueden ser menos claras en su código que anidadas para bucles, ya que los bucles for se analizan fácilmente visualmente.

4

Dado que son expresiones de generador, puede vincular cada una a su propio nombre para hacerlo más legible sin ningún cambio en el rendimiento. Cambiarlo a un bucle anidado probablemente sea perjudicial para el rendimiento.

irange = (i for i in xrange(10)) 
jrange = (j for j in irange) 
krange = (k for k in jrange) 

Realmente no importa que usted elija, creo que el ejemplo de varias líneas es más fácil de leer, en general.

5

En el caso de tu ejemplo, probablemente escribir como:

foos = (i for i in xrange(10)) 
bars = (j for j in foos) 
bazs = (k for k in bars) 

dado nombres más descriptivos, creo que esto sería probablemente muy claro, y no puedo imaginar que exista ninguna posibilidad de medir diferencia.

Tal vez usted está pensando más en expresiones como:

(x for x in xs for xs in ys for ys in lst) 

- en realidad, eso ni siquiera es válido. Usted tiene que poner las cosas en otro orden:

(x for ys in lst for xs in ys for x in xs) 

Yo podría escribir que como una forma rápida de aplanar una lista, pero en general creo que eres de escritura: el tiempo que se ahorra escribiendo menos suele ser equilibrada por el tiempo extra que pasa obteniendo la expresión del generador correcta.

12

Si usted está preocupado acerca demasiada complejidad en una línea, se podría dividir:

(k for k in 
    (j for j in 
     (i for i in xrange(10)))) 

continuaciones de línea Siempre he encontrado que mirar un poco raro en Python, pero esto hace que sea más fácil para ver lo que cada uno está dando vueltas. Desde una misión/de búsqueda adicional no se va a hacer o romper nada, también se puede escribir así:

gen1 = (i for i in xrange(10)) 
gen2 = (j for j in gen1) 
gen3 = (k for k in gen2) 

En la práctica, no creo que haya anidado una comprensión más profunda de 2 , y en ese punto todavía era bastante fácil de entender.

+0

Eliminé los escapes. – Soviut

0

La expresión:

(k for k in (j for j in (i for i in xrange(10)))) 

es equivalente a:

(i for i in xrange(10)) 

que es casi lo mismo:

xrange(10) 

La última variante es más elegante que la primera.

0

me parece que puede ser útil y elegante en situaciones como estas, donde tienes un código como éste:

output = [] 
for item in list: 
    if item >= 1: 
     new = item += 1 
     output.append(new) 

Se puede hacer una sola línea como esta:

output = [item += 1 for item in list if item >= 1] 
1

Advertencia: la elegancia es en parte una cuestión de gusto.

Las comprensiones de listas nunca son más claro que el correspondiente expandido para el bucle. Para los bucles también son más poderosos que las listas de comprensión. Entonces, ¿por qué usarlos?

Lo que la comprensión de la lista es conciso - le permiten hacer algo en una sola línea.

El tiempo para usar una lista de comprensión es cuando necesita una determinada lista, se puede crear sobre la marcha con bastante facilidad, y no desea o necesita objetos intermedios. Esto puede ocurrir cuando se necesita para empaquetar algunos objetos en el ámbito actual en un solo objeto que se puede alimentar a una función, como a continuación:

list1 = ['foo', 'bar'] 
list2 = ['-ness', '-ity'] 
return filterRealWords([str1+str2 for str1 in list1 for str2 in list2]) 

Este código es lo más fácil de leer que la versión ampliada, pero es mucho más corto. Evita crear/nombrar un objeto que solo se usa una vez en el ámbito actual, que es posiblemente más elegante.

Cuestiones relacionadas