Python Language Lista de Comprensiones


Ejemplo

Una lista de comprensión crea una nueva list al aplicar una expresión a cada elemento de un iterable . La forma más básica es:

[ <expression> for <element> in <iterable> ]

También hay una condición opcional "si":

[ <expression> for <element> in <iterable> if <condition> ]

Cada <element> en el <iterable> se conecta a la <expression> si el <condition> (opcional) se evalúa como verdadero . Todos los resultados se devuelven a la vez en la nueva lista. Las expresiones de los generadores se evalúan perezosamente, pero las comprensiones de la lista evalúan todo el iterador inmediatamente, consumiendo memoria proporcional a la longitud del iterador.

Para crear una list de enteros cuadrados:

squares = [x * x for x in (1, 2, 3, 4)]
# squares: [1, 4, 9, 16]

La expresión for establece x a cada valor por turno de (1, 2, 3, 4) . El resultado de la expresión x * x se anexa a una list interna. La list interna se asigna a los squares variables cuando se completa.

Además de un aumento de velocidad (como se explica aquí ), una comprensión de la lista es aproximadamente equivalente al siguiente bucle for:

squares = []
for x in (1, 2, 3, 4):
    squares.append(x * x)
# squares: [1, 4, 9, 16]

La expresión aplicada a cada elemento puede ser tan compleja como sea necesario:

# Get a list of uppercase characters from a string
[s.upper() for s in "Hello World"]
# ['H', 'E', 'L', 'L', 'O', ' ', 'W', 'O', 'R', 'L', 'D']

# Strip off any commas from the end of strings in a list
[w.strip(',') for w in ['these,', 'words,,', 'mostly', 'have,commas,']]
# ['these', 'words', 'mostly', 'have,commas']

# Organize letters in words more reasonably - in an alphabetical order
sentence = "Beautiful is better than ugly"
["".join(sorted(word, key = lambda x: x.lower())) for word in sentence.split()]
# ['aBefiltuu', 'is', 'beertt', 'ahnt', 'gluy']

más

else se puede utilizar en las construcciones de comprensión de listas, pero tenga cuidado con la sintaxis. Las cláusulas if / else deben usarse antes for bucle, no después:

# create a list of characters in apple, replacing non vowels with '*'
# Ex - 'apple' --> ['a', '*', '*', '*' ,'e']

[x for x in 'apple' if x in 'aeiou' else '*']
#SyntaxError: invalid syntax

# When using if/else together use them before the loop
[x if x in 'aeiou' else '*' for x in 'apple']
#['a', '*', '*', '*', 'e']

Tenga en cuenta que esto utiliza una construcción de lenguaje diferente, una expresión condicional , que en sí misma no es parte de la sintaxis de comprensión . Considerando que el if after the for…in es parte de la lista de comprensión y se utiliza para filtrar elementos de la fuente iterable.


Doble iteración

El orden de doble iteración [... for x in ... for y in ...] es natural o contraintuitivo. La regla de oro es seguir un equivalente for bucle:

def foo(i):
    return i, i + 0.5

for i in range(3):
    for x in foo(i):
        yield str(x)

Esto se convierte en:

[str(x)
    for i in range(3)
        for x in foo(i)
]

Esto se puede comprimir en una línea como [str(x) for i in range(3) for x in foo(i)]


Mutación in situ y otros efectos secundarios

Antes de usar la comprensión de lista, comprenda la diferencia entre las funciones solicitadas por sus efectos secundarios (funciones mutantes o en el lugar ) que generalmente devuelven None y las funciones que devuelven un valor interesante.

Muchas funciones (especialmente funciones puras ) simplemente toman un objeto y devuelven algún objeto. Una función en el lugar modifica el objeto existente, que se denomina efecto secundario . Otros ejemplos incluyen operaciones de entrada y salida, como la impresión.

list.sort() ordena una lista en el lugar (lo que significa que modifica la lista original) y devuelve el valor None . Por lo tanto, no funcionará como se espera en una lista de comprensión:

[x.sort() for x in [[2, 1], [4, 3], [0, 1]]]
# [None, None, None]

En su lugar, sorted() devuelve una list ordenada en lugar de ordenar in situ:

[sorted(x) for x in [[2, 1], [4, 3], [0, 1]]]
# [[1, 2], [3, 4], [0, 1]]

Es posible el uso de comprensiones para efectos secundarios, como I / O o funciones in situ. Sin embargo, un bucle for suele ser más legible. Mientras esto funciona en Python 3:

[print(x) for x in (1, 2, 3)]

En su lugar, utilice:

for x in (1, 2, 3):
    print(x)

En algunas situaciones, las funciones de efectos secundarios son adecuadas para la comprensión de listas. random.randrange() tiene el efecto secundario de cambiar el estado del generador de números aleatorios, pero también devuelve un valor interesante. Además, se puede llamar a next() en un iterador.

El siguiente generador de valores aleatorios no es puro, pero tiene sentido ya que el generador aleatorio se restablece cada vez que se evalúa la expresión:

from random import randrange
[randrange(1, 7) for _ in range(10)]
# [2, 3, 2, 1, 1, 5, 2, 4, 3, 5]

Los espacios en blanco en la lista de comprensión

Las comprensiones de listas más complicadas pueden alcanzar una longitud no deseada o volverse menos legibles. Aunque es menos común en los ejemplos, es posible dividir una lista de comprensión en varias líneas, como por ejemplo:

[
    x for x
    in 'foo'
    if x not in 'bar'
]