Las comprensiones de lista (list comprehensions) son una de las características más elegantes y poderosas del lenguaje Python. Permiten crear nuevas listas de forma concisa, aplicando transformaciones y filtros en una sola línea de código, reemplazando bucles tradicionales y funciones como map() y filter() en la mayoría de los casos.
Si estás empezando en el mundo Python, dominar las comprensiones de lista elevará significativamente la calidad y legibilidad de tu código. En esta guía completa aprenderás desde la sintaxis básica hasta técnicas avanzadas, con ejemplos prácticos que puedes aplicar inmediatamente.
¿Qué son las Comprensiones de Lista?
Una comprensión de lista es una construcción sintáctica que permite crear una nueva lista iterando sobre una secuencia existente (o cualquier iterable) y opcionalmente aplicando una condición de filtro. La sintaxis básica es:
[nueva_expresion for item in iterable if condicion]
La expresión nueva_expresion se calcula para cada elemento que satisface la condicion (si la hay), y el resultado se añade a la nueva lista.
Sintaxis Básica
Comencemos con el ejemplo más simple: crear una lista con los cuadrados de los números del 0 al 9.
Usando un bucle for tradicional:
cuadrados = []
for numero in range(10):
cuadrados.append(numero ** 2)
print(cuadrados) # [0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
Con comprensión de lista:
cuadrados = [numero ** 2 for numero in range(10)]
print(cuadrados) # [0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
La diferencia es notable: en una sola línea eliminamos la necesidad de inicializar la lista vacía, escribir el bucle y llamar a append(). El código queda más limpio, más legible y, en la mayoría de los casos, más rápido.
Según la documentación oficial de Python, las comprensiones de lista consisten en corchetes que contienen una expresión seguida de una cláusula for y cero o más cláusulas for o if.
¿Por qué Usar Comprensiones de Lista?
Las comprensiones de lista ofrecen tres ventajas principales frente a los bucles tradicionales:
- Concisión: reducen varias líneas de código a una sola expresión
- Legibilidad: una vez que aprendes la sintaxis, el código expresa claramente la intención
- Rendimiento: generalmente son más rápidas que los bucles
forequivalentes
Analicemos la diferencia de rendimiento con un ejemplo práctico. Crear una lista con los números pares del 0 al 999999:
import time
inicio = time.time()
pares_bucle = []
for i in range(1000000):
if i % 2 == 0:
pares_bucle.append(i)
fin_bucle = time.time()
inicio = time.time()
pares_comp = [i for i in range(1000000) if i % 2 == 0]
fin_comp = time.time()
print(f"Bucle for: {fin_bucle - inicio:.4f}s")
print(f"Comprensión: {fin_comp - inicio:.4f}s")
En la práctica, las comprensiones de lista son significativamente más rápidas porque la operación se ejecuta en C internamente, sin la sobrecarga de llamar al método append() en cada iteración. Esta ganancia de rendimiento es especialmente relevante cuando procesas grandes volúmenes de datos.
El PEP 202, que introdujo las comprensiones de lista en Python 2.0, explica la motivación detrás de esta característica: proporcionar una manera más sucinta y legible de crear listas basadas en secuencias existentes.
Ejemplos Prácticos del Día a Día
1. Transformación de Cadenas
Convertir una lista de cadenas a mayúsculas:
nombres = ['ana', 'juan', 'maría', 'pedro']
nombres_mayus = [nombre.upper() for nombre in nombres]
print(nombres_mayus) # ['ANA', 'JUAN', 'MARÍA', 'PEDRO']
2. Filtrado con Condicional
Seleccionar solo los números pares:
numeros = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
pares = [num for num in numeros if num % 2 == 0]
print(pares) # [2, 4, 6, 8, 10]
3. Transformación con Condicional (if-else)
A diferencia del if filtrante, puedes usar if-else antes del for para transformar condicionalmente:
numeros = [1, 2, 3, 4, 5]
etiquetas = ['par' if num % 2 == 0 else 'impar' for num in numeros]
print(etiquetas) # ['impar', 'par', 'impar', 'par', 'impar']
4. Aplanamiento de Matrices
Convertir una matriz 2D en una lista 1D:
matriz = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
plano = [num for fila in matriz for num in fila]
print(plano) # [1, 2, 3, 4, 5, 6, 7, 8, 9]
5. Aplicar Función a Elementos
def celsius_a_fahrenheit(c):
return (c * 9/5) + 32
temps_c = [0, 10, 20, 30, 40]
temps_f = [celsius_a_fahrenheit(c) for c in temps_c]
print(temps_f) # [32.0, 50.0, 68.0, 86.0, 104.0]
6. Extraer Datos de Diccionarios
alumnos = [
{'nombre': 'Ana', 'nota': 8.5},
{'nombre': 'Juan', 'nota': 6.0},
{'nombre': 'María', 'nota': 9.2},
{'nombre': 'Pedro', 'nota': 4.5}
]
aprobados = [alumno['nombre'] for alumno in alumnos if alumno['nota'] >= 7.0]
print(aprobados) # ['Ana', 'María']
Comprensiones de Lista Anidadas
Las comprensiones anidadas son útiles para trabajar con estructuras de datos multidimensionales. Creemos una matriz identidad 4x4:
n = 4
identidad = [[1 if i == j else 0 for j in range(n)] for i in range(n)]
for fila in identidad:
print(fila)
# [1, 0, 0, 0]
# [0, 1, 0, 0]
# [0, 0, 1, 0]
# [0, 0, 0, 1]
Otro ejemplo clásico: transponer una matriz:
matriz = [[1, 2, 3], [4, 5, 6]]
transpuesta = [[fila[i] for fila in matriz] for i in range(3)]
print(transpuesta) # [[1, 4], [2, 5], [3, 6]]
Comprensiones con Múltiples Condiciones
Puedes encadenar múltiples condiciones if:
numeros = range(1, 51)
filtrados = [n for n in numeros if n % 2 == 0 if n % 5 == 0]
print(filtrados) # [10, 20, 30, 40, 50]
# Equivalente a: if n % 2 == 0 and n % 5 == 0
Comprensiones de Lista vs map() y filter()
Python ofrece las funciones map() y filter() de la programación funcional, que pueden hacer cosas similares:
numeros = [1, 2, 3, 4, 5]
# Usando map()
cuadrados_map = list(map(lambda x: x ** 2, numeros))
# Usando comprensión
cuadrados_comp = [x ** 2 for x in numeros]
# Usando filter()
pares_filter = list(filter(lambda x: x % 2 == 0, numeros))
# Usando comprensión
pares_comp = [x for x in numeros if x % 2 == 0]
La comunidad Python y el propio Guido van Rossum recomiendan usar comprensiones de lista en lugar de map() y filter() con lambda, ya que el código resulta más legible.
El tutorial de Real Python sobre list comprehensions profundiza aún más en esta comparación y muestra benchmarks detallados.
Buenas Prácticas
1. Mantén la Simplicidad
Si la comprensión de lista se vuelve demasiado larga o compleja, prefiere usar un bucle tradicional. Una buena regla es: si la comprensión supera los 80 caracteres, considera dividirla en varias líneas o usar un bucle.
# Mal (demasiado larga)
resultado = [funcion_complicada(x, y) for x in lista_x for y in lista_y if condicion_1(x) and condicion_2(y) and validacion(x, y)]
# Mejor (bucle explícito)
resultado = []
for x in lista_x:
for y in lista_y:
if condicion_1(x) and condicion_2(y) and validacion(x, y):
resultado.append(funcion_complicada(x, y))
2. Usa Generadores para Grandes Volúmenes
Si estás procesando una cantidad muy grande de datos y no necesitas almacenar todos los resultados en memoria, usa una expresión generadora (con paréntesis en lugar de corchetes):
# Comprensión de lista (todo en memoria)
cuadrados_lista = [x ** 2 for x in range(10_000_000)]
# Expresión generadora (evaluación perezosa)
cuadrados_gen = (x ** 2 for x in range(10_000_000))
# Itera bajo demanda
for valor in cuadrados_gen:
if valor > 100:
break
El sitio GeeksforGeeks tiene una excelente sección comparando generadores y list comprehensions con ejemplos prácticos.
3. Evita Efectos Secundarios
Las comprensiones de lista deben usarse para crear nuevas listas, no por sus efectos secundarios. Evita:
# Mal (efecto secundario)
[print(item) for item in lista]
# Bien
for item in lista:
print(item)
4. Prefiere Comprensiones a map()/filter() con lambda
A menos que ya tengas una función definida, las comprensiones son más legibles:
# Comprensión (legible)
resultados = [len(palabra) for palabra in palabras]
# map con lambda (menos legible)
resultados = list(map(lambda p: len(p), palabras))
# map con función existente (ok)
resultados = list(map(len, palabras))
Casos de Uso Avanzados
List Comprehensions con zip()
Combinar listas paralelas:
nombres = ['Ana', 'Juan', 'María']
edades = [25, 32, 28]
personas = [f'{nombre} tiene {edad} años' for nombre, edad in zip(nombres, edades)]
print(personas) # ['Ana tiene 25 años', 'Juan tiene 32 años', 'María tiene 28 años']
Comprensiones con else (Operador Ternario)
valores = [10, -5, 0, 8, -3, 15]
clasificados = ['positivo' if v > 0 else 'negativo' if v < 0 else 'cero' for v in valores]
print(clasificados) # ['positivo', 'negativo', 'cero', 'positivo', 'negativo', 'positivo']
Comprensiones con enumerate()
palabras = ['python', 'seo', 'artículo', 'código']
con_indices = [(i, palabra.upper()) for i, palabra in enumerate(palabras)]
print(con_indices) # [(0, 'PYTHON'), (1, 'SEO'), (2, 'ARTÍCULO'), (3, 'CÓDIGO')]
Cuándo NO Usar Comprensiones de Lista
A pesar de su poder, existen situaciones en las que las comprensiones de lista no son la mejor opción:
- Lógica muy compleja: bucles con múltiples condicionales anidados y transformaciones extensas
- Depuración: es más fácil añadir
print()o usar un depurador con bucles tradicionales - Grandes volúmenes con memoria limitada: usa expresiones generadoras
- Cuando necesitas interrumpir el bucle anticipadamente (
break) - Cuando necesitas modificar la lista original directamente
El tutorial de W3Schools tiene una introducción amigable que aborda los fundamentos para principiantes.
Comparación con Otros Lenguajes
Si vienes de otros lenguajes, aquí tienes una comparación rápida:
JavaScript (Array.map + filter):
let numeros = [1, 2, 3, 4, 5];
let paresCuadrados = numeros.filter(n => n % 2 === 0).map(n => n ** 2);
// [4, 16]
Python (list comprehension):
numeros = [1, 2, 3, 4, 5]
pares_cuadrados = [n ** 2 for n in numeros if n % 2 == 0]
# [4, 16]
La sintaxis de Python se considera generalmente más limpia para esta operación específica.
Conclusión
Las comprensiones de lista son una de las características más distintivas y útiles de Python. Permiten escribir código más limpio, más rápido y más expresivo. Dominar esta característica es esencial para cualquier programador Python, ya seas un principiante o un profesional experimentado.
Recuerda las lecciones principales:
- Usa comprensiones para reemplazar bucles simples de transformación y filtro
- Mantén tus comprensiones legibles y concisas
- Prefiere expresiones generadoras para grandes conjuntos de datos
- Evita efectos secundarios dentro de las comprensiones
- Conoce los límites: no todo debe ser una comprensión de lista
Programiz ofrece más ejemplos interactivos para que practiques y consolides el conocimiento.
Ahora que entiendes el poder de las comprensiones de lista, practica con tus propios datos. Intenta refactorizar bucles antiguos de tus proyectos para usar comprensiones — te sorprenderá la diferencia en la calidad del código. Sigue estudiando y explorando el ecosistema Python para descubrir aún más características que hacen de este lenguaje algo tan especial.