2008-11-22 19 views
46

Las comprensiones de listas pueden ser útiles en ciertas situaciones, pero también pueden ser bastante horribles de leer ... Como ejemplo ligeramente exagerado, ¿cómo sangraría lo siguiente?¿Cómo se sangran las listas de comprensión de Python?

allUuids = [x.id for x in self.db.query(schema.allPostsUuid).execute(timeout = 20) if x.type == "post" and x.deleted is not False] 

Respuesta

55

Depende de cuánto tiempo son. Tiendo a estructurarlos así:

[x.id for x 
in self.db.query(schema.allPostsUuid).execute(timeout=20) 
if x.type == 'post' 
    and x.deleted is not False 
    and ... 
    and ...] 

De esta forma cada expresión tiene su propia línea.

Si cualquier línea se vuelve demasiado grande me gusta para extraerlo en una lambda o expresión:

transform = lambda x: x.id 
results = self.db.query(schema.allPostsUuid).execute(timeout=20) 
condition = lambda x: x.deleted is not False and ... and ... 
[transform(x) for x in results if condition(x)] 

Y luego, si un lambda se hace demasiado tiempo que se promueve a una función.

+3

estos NO son equivalentes, la comprensión de la lista es mucho más rápida, ya que no tiene que hacer ninguna búsqueda de función. la traducción apropiada usaría para bucles. – Claudiu

+2

¡Excepto por el golpe de rendimiento, este es un ejemplo muy legible! – Geo

+1

¿Cómo evitarían los bucles for la función de búsqueda? También tenga en cuenta que el ciclo en la lista de comprensiones se implementa en C, y por lo tanto es más rápido que el simple. – orestis

1

¿Qué tal:

allUuids = [x.id for x in self.db.query(schema.allPostsUuid).execute(timeout = 20) 
        if (x.type == "post" and x.deleted is not False)] 

En general, las líneas largas se pueden evitar subexpresiones pre-computación en variables, lo que podría añadir un costo de rendimiento minúscula:

query_ids = self.db.query(schema.allPostsUuid).execute(timeout = 20) 
allUuids = [x.id for x in query_ids 
        if (x.type == "post" and x.deleted is not False)] 

Por cierto , no es 'is not False' tipo de superfluo? ¿Te preocupa diferenciar entre Ninguno y Falso? Porque de lo contrario, es suficiente dejar la condición como solo: i f (x.type == "post" and x.deleted)

+0

Secundo eso. En general, se deben evitar las líneas de más de 80 caracteres en todos los idiomas. –

+0

De acuerdo, pero las reglas de sintaxis de Python a menudo alientan/fuerzan líneas más largas. Su manejo del espacio en blanco es mi única queja sobre el lenguaje. –

+0

Con las variables cuidadosamente seleccionadas, y las líneas de división con paréntesis o corchetes, nunca tuve que recurrir a líneas demasiado largas (el problema es más a menudo para evitar self.long_foo.very_long_bar.baz (....) usando temporarios) –

5

Para mí eso es demasiado. Tal vez es solo un ejemplo terrible, ya que "tipo" y "eliminado" serían claramente parte de la consulta db.

Tiendo a pensar que si una lista de comprensión abarca múltiples líneas, probablemente no debería ser una lista de comprensión. Habiendo dicho eso, por lo general solo lo divido en "si" como lo han hecho otras personas y responderé aquí.

37

Donde trabajo, nuestras directrices de codificación quiere que hagamos algo como esto:

all_posts_uuid_query = self.db.query(schema.allPostsUuid) 
all_posts_uuid_list = all_posts_uuid_query.execute(timeout=20) 
all_uuid_list = [ 
    x.id 
    for x in all_posts_uuid_list 
    if (
     x.type == "post" 
     and 
     not x.deleted # <-- if you don't care about NULLs/None 
    ) 
] 
+0

Eso es bastante bonito. –

+0

Así es como lo hago – orip

5
allUuids = [x.id 
      for x in self.db.query(schema.allPostsUuid).execute(timeout = 20) 
      if x.type == "post" and x.deleted is not False] 
5

No use una lista por comprensión para que.

Las comprensiones de listas son una característica increíble, pero se supone que son accesos directos, no un código normal.

Durante mucho fragmento tal, debe utilizar bloques ordinarios:

allUuids = [] 
for x in self.db.query(schema.allPostsUuid).execute(timeout = 20) : 
    if x.type == "post" and x.deleted is not False : 
     allUuids.append(x.id) 

exactamente el mismo comportamiento, mucho más legible. Guido estaría orgulloso de ti :-)

+0

esto es un poco más lento, ya que tienes que construir la matriz paso a paso – Claudiu

+0

Creo que la comprensión de la lista hace exactamente lo mismo bajo el capó. No es porque sea una expresión de una sola línea que esta es una operación de una sola vez ... –

+1

e-statis: la función es la misma, pero la lista de comprensiones puede ser significativamente más rápida – orip

0

Si tienes una comprensión orestis's answer es bueno.

Para comprensiones más complejos como el que me gustaría sugerir el uso de un generador con yield:

allUuids = list(self.get_all_uuids()) 


def get_all_uuids(self): 
    for x in self.db.query(schema.allPostsUuid).execute(timeout = 20): 
     if x.type == "post" and x.deleted is not False: 
      yield x.id 
Cuestiones relacionadas