Las comprensiones de listas (list comprehensions) son una forma concisa de crear listas basadas en objetos iterables existentes mediante una sintaxis corta:
squares = [x**2 for x in range(10)]
Esta escritura es equivalente a:
squares = [] for x in range(10): squares.append(x**2)
Las comprensiones de listas tienen varias ventajas:
evens = [x for x in range(10) if x % 2 == 0];Analogía con map():
def f(x): return x**2 squares = list(map(f, range(10)))
map es más rápido en grandes datos si se utiliza una función que ya existe en C y es adecuado para aplicar una función a todos los elementos. La comprensión de listas es para cualquier expresión, no solo para funciones predefinidas. El bucle for es más flexible, pero más voluminoso.
¿Por qué en una expresión como
[x for x in range(10)]la variable x después de la ejecución de la lista es accesible fuera de la expresión en Python2, pero no en Python3?
Respuesta: En Python2, la variable de bucle (x) mantiene su valor después de ejecutar la comprensión de listas. En Python3, se "aisla" y no está disponible fuera de la lista, lo que previene efectos secundarios no deseados.
Ejemplo:
# Python 2.x: [x for x in range(3)] print(x) # x == 2 # Python 3.x: [x for x in range(3)] print(x) # NameError: name 'x' is not defined
Historia 1
Un desarrollador en un gran proyecto quería filtrar y crear una nueva lista a través de la comprensión de listas:
my_list = [item.transform() for item in data if item.is_valid()]
Pero la operación item.transform() lanzaba un error si item.is_valid() devolvía False. Sin embargo, la función de verificación fue escrita con un posible efecto secundario, y al final la comprensión de listas rompía partes del código de manera no obvia debido a esos efectos secundarios.
Historia 2
En un proyecto al migrar de Python2 a Python3, un desarrollador estaba seguro de que la variable de bucle permanecería accesible:
[x for x in range(5)] print(x) # Esperaba obtener 4, pero obtuvo NameError.
Esto causó un bug en la lógica cíclica, donde la variable debía permanecer accesible fuera de la comprensión.
Historia 3
Uso de comprensiones de listas anidadas sin especificar claramente los niveles:
def flatten(matrix): return [cell for row in matrix for cell in row]
Los principiantes a menudo cometen errores debido al orden de iteración incorrecto (por ejemplo, [cell for cell in row for row in matrix] o anidaciones innecesarias), lo que lleva a un resultado incorrecto: una lista unidimensional en lugar de bidimensional o viceversa.