List comprehensions en Python — La guía completa con ejemplos

Si llevas un tiempo programando Python, seguro que has visto código tipo [x*2 for x in numeros] y te has quedado mirando la pantalla pensando: “¿qué brujería es esto?”. Tranquilo, le pasa a todo el mundo la primera vez.
Las list comprehensions son una de las cosas más Python de Python. Una vez las dominas, ves bucles con append y te da picor leer el código. Esta entrada es la guía definitiva: desde lo básico hasta los trucos que casi nadie cuenta — incluido cuándo no usarlas (sí, hay casos donde son peor que un bucle normal).
Contenido
- 1 Qué es una list comprehension
- 2 La sintaxis, despiezada
- 3 Filtros: añadir un if
- 4 Transformaciones: cambiar lo que guardas
- 5 Combinando transformación + filtro
- 6 El if/else en la expresión (cuidado, distinto al filtro)
- 7 Comprehensions anidadas: dos for
- 8 Lista de listas: anidación a la inversa
- 9 Hermanas de las list comprehensions
- 10 Cuándo NO usar list comprehensions
- 11 Errores típicos
- 12 Resumen rápido
- 13 Tu siguiente paso
Qué es una list comprehension
Una list comprehension es una forma compacta de crear una lista a partir de otra cosa iterable (una lista, una tupla, un range, un string…) en una sola línea.
La forma larga, que ya conoces, es esta:
numeros = [1, 2, 3, 4, 5]
dobles = []
for n in numeros:
dobles.append(n * 2)
print(dobles) # [2, 4, 6, 8, 10]
Cuatro líneas para algo tan simple. La forma compacta:
numeros = [1, 2, 3, 4, 5]
dobles = [n * 2 for n in numeros]
print(dobles) # [2, 4, 6, 8, 10]
Una línea. Mismo resultado. Más rápido (Python las optimiza internamente). Y, una vez te acostumbras, mucho más legible.
La sintaxis, despiezada
La estructura es siempre la misma:
[ expresion for variable in iterable ]
↑ ↑
qué guardas de dónde lo saco
Si lo lees de izquierda a derecha:
“Crea una lista con
n*2para cadanque esté ennumeros.”
Pista mental: lee la línea como una frase en inglés (“multiply n by 2 for each n in numeros“) y la entiendes a la primera.
Filtros: añadir un if
Aquí empieza la magia. Puedes añadir un filtro al final:
numeros = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
pares = [n for n in numeros if n % 2 == 0]
print(pares) # [2, 4, 6, 8, 10]
Lectura: “guarda n para cada n en numeros si n es par”.
Equivalente largo (para que veas lo que ahorras):
pares = []
for n in numeros:
if n % 2 == 0:
pares.append(n)
Otro ejemplo más útil — quedarse con palabras largas:
palabras = ["sol", "elefante", "luz", "extraordinario", "casa"]
largas = [p for p in palabras if len(p) > 4]
print(largas) # ['elefante', 'extraordinario']
📥 Llévate el cheatsheet de Python (gratis)
PDF de 6 páginas con lo esencial: tipos, condicionales, bucles, estructuras de datos, funciones y los errores que más vas a cometer. Para tener al lado mientras programas.
Sin spam. Te apuntas a la lista, descargas el cheatsheet y recibes contenido de Python cada semana.
Transformaciones: cambiar lo que guardas
La parte de la izquierda no tiene por qué ser la variable tal cual — puede ser cualquier expresión:
nombres = ["ana", "PEDRO", "Luis", "MARÍA"]
# Capitalizar todos
capitalizados = [n.capitalize() for n in nombres]
print(capitalizados) # ['Ana', 'Pedro', 'Luis', 'María']
# Longitud de cada nombre
longitudes = [len(n) for n in nombres]
print(longitudes) # [3, 5, 4, 5]
# Tuplas (nombre, longitud)
con_longitud = [(n.capitalize(), len(n)) for n in nombres]
print(con_longitud) # [('Ana', 3), ('Pedro', 5), ('Luis', 4), ('María', 5)]
Combinando transformación + filtro
Lo típico que harás el 80% del tiempo:
numeros = range(1, 11) # 1 a 10
# Cuadrados de los pares
cuadrados_pares = [n ** 2 for n in numeros if n % 2 == 0]
print(cuadrados_pares) # [4, 16, 36, 64, 100]
Y un caso más realista — limpiar y filtrar datos de un formulario:
respuestas = [" ", "Madrid", "barcelona ", "", " VALENCIA"]
# Quitar espacios, capitalizar y dejar solo las que tengan algo
ciudades = [r.strip().capitalize() for r in respuestas if r.strip()]
print(ciudades) # ['Madrid', 'Barcelona', 'Valencia']
Tres operaciones (strip, capitalize, filtro) en una línea. Ahí es donde brillan.
El if/else en la expresión (cuidado, distinto al filtro)
Mucha gente se lía con esto al principio. Hay dos formas de meter un if en una list comprehension:
numeros = [1, 2, 3, 4, 5, 6]
# Forma 1 — FILTRO (al final): mantiene solo los que cumplen
filtrados = [n for n in numeros if n % 2 == 0]
print(filtrados) # [2, 4, 6]
# Forma 2 — TERNARIO (en la expresión): siempre incluye, pero transforma
etiquetados = ["par" if n % 2 == 0 else "impar" for n in numeros]
print(etiquetados) # ['impar', 'par', 'impar', 'par', 'impar', 'par']
Diferencia clave:
- Filtro
ifal final: decide si incluir el elemento. La lista resultante tiene igual o menos elementos. - Ternario
if/elseal principio: decide qué guardas para cada elemento. La lista resultante tiene el mismo número de elementos.
⚠️ Atención: si quieres
if/elseen la expresión, necesitas elelse. Si solo quieres filtrar, va al final sinelse. Mezclar las dos sintaxis es el error más común al empezar.
Comprehensions anidadas: dos for
Cuando trabajas con listas de listas (matrices, datos tabulares…) puedes anidar:
# Aplanar una matriz 2D a una lista 1D
matriz = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
plana = [n for fila in matriz for n in fila]
print(plana) # [1, 2, 3, 4, 5, 6, 7, 8, 9]
Lectura: “para cada fila en matriz, para cada n en fila, guarda n“. El orden es el mismo que tendría el bucle anidado:
plana = []
for fila in matriz: # bucle externo
for n in fila: # bucle interno
plana.append(n)
Otro caso típico — pares de combinaciones:
# Producto cartesiano de dos listas
colores = ["rojo", "azul"]
tallas = ["S", "M", "L"]
combinaciones = [(c, t) for c in colores for t in tallas]
print(combinaciones)
# [('rojo', 'S'), ('rojo', 'M'), ('rojo', 'L'),
# ('azul', 'S'), ('azul', 'M'), ('azul', 'L')]
💡 Tip-friki: si usas mucho producto cartesiano, mira
itertools.product. Hace lo mismo más explícito y compone mejor con otros iterables:list(product(colores, tallas)).
Lista de listas: anidación a la inversa
Si lo que quieres es construir una matriz, la expresión es una lista entera:
# Tabla de multiplicar 3x3
tabla = [[i * j for j in range(1, 4)] for i in range(1, 4)]
print(tabla)
# [[1, 2, 3],
# [2, 4, 6],
# [3, 6, 9]]
Lectura: “por cada i de 1 a 3, crea una lista con i*j para j de 1 a 3″. El bucle externo controla las filas; el interno controla los valores dentro de la fila.
Hermanas de las list comprehensions
Python tiene la misma sintaxis para crear otros tipos de colecciones.
Dict comprehension
Para construir diccionarios:
nombres = ["ana", "pedro", "luis"]
# Diccionario nombre → longitud
longitudes = {n: len(n) for n in nombres}
print(longitudes) # {'ana': 3, 'pedro': 5, 'luis': 4}
# Invertir un diccionario
edades = {"Ana": 30, "Pedro": 25, "Luis": 40}
invertido = {edad: nombre for nombre, edad in edades.items()}
print(invertido) # {30: 'Ana', 25: 'Pedro', 40: 'Luis'}
Set comprehension
Para construir sets (conjuntos sin duplicados):
texto = "el pythonista"
# Letras únicas (sin espacios)
letras = {c for c in texto if c != " "}
print(letras) # {'e', 'l', 'p', 'y', 't', 'h', 'o', 'n', 'i', 's', 'a'}
Generator expression (la “list comprehension” con paréntesis)
Cambias [] por () y tienes un generador — un iterable perezoso que no construye la lista entera en memoria:
numeros = range(1_000_000)
# List comprehension: crea lista entera en memoria (8 MB+)
suma_lista = sum([n ** 2 for n in numeros])
# Generator expression: genera valor a valor, casi cero memoria
suma_gen = sum(n ** 2 for n in numeros)
Cuando el resultado lo vas a consumir solo una vez (sumar, contar, pasar a max/min/any/all), usa generator. Cuando necesitas la lista para algo más (acceso por índice, recorrer dos veces…), usa list.
Cuándo NO usar list comprehensions
Aquí va la parte que casi nadie cuenta. Las comprehensions son una herramienta — no la solución a todo. Hay 3 casos en los que un bucle clásico es mejor:
1. Cuando hay efectos secundarios
Si solo quieres ejecutar algo por cada elemento (imprimir, escribir en un fichero, mandar a una API), NO uses comprehension. Genera una lista que tiras a la basura.
# MAL: creas una lista de Nones para nada
[print(n) for n in [1, 2, 3]]
# BIEN
for n in [1, 2, 3]:
print(n)
2. Cuando hay lógica de varias líneas
Si tu expresión necesita varias líneas, try/except, o múltiples if anidados, un bucle es más legible:
# MAL: ilegible, todo apretado
resultados = [parsear(x) for x in datos if x.startswith("v") and len(x) > 3 and x not in vistos]
# MEJOR: bucle clásico
resultados = []
for x in datos:
if not x.startswith("v"):
continue
if len(x) <= 3:
continue
if x in vistos:
continue
resultados.append(parsear(x))
3. Cuando anidas más de 2 for
Una comprehension con 3 niveles anidados es ilegible. Punto. Bucle clásico, fin de la discusión.
Errores típicos
Tres clásicos que cometen todos los principiantes (yo el primero):
# 1. Olvidar el else en el ternario
# MAL: SyntaxError
[x if x > 0 for x in numeros]
# BIEN: con else
[x if x > 0 else 0 for x in numeros]
# 2. Usar la variable del bucle fuera de la comprehension
[n*2 for n in range(5)]
print(n) # En Python 3 esto da NameError. En Python 2 ¡estaba en scope!
# 3. Asumir que es siempre más rápido
# Una comprehension simple suele serlo, pero no por arte de magia.
# Si dentro llamas a una función pesada, será igual de lento que un for.
Resumen rápido
| Quiero… | Sintaxis |
|---|---|
| Lista a partir de iterable | [expr for x in iterable] |
| Lista filtrada | [expr for x in iterable if cond] |
| Lista con transformación condicional | [a if cond else b for x in iterable] |
| Diccionario | {k: v for x in iterable} |
| Set | {expr for x in iterable} |
| Generador (lazy) | (expr for x in iterable) |
Y la regla de oro: si la comprehension cabe cómoda en una línea legible, úsala. Si no, vuelve al bucle. No es estilo viejo — es código mantenible.
¿Te ha valido esto?
Si te ha resultado útil, llévate el cheatsheet de Python en PDF — 6 páginas con tipos, condicionales, bucles, estructuras de datos, funciones y los errores típicos. Para tener al lado mientras programas. Gratis.
Sin spam. Email + cheatsheet + un correo por semana con tutoriales nuevos.
Tu siguiente paso
Si has llegado hasta aquí, ya manejas list comprehensions mejor que el 70% de la gente que escribe Python. El siguiente paso es practicarlas en código real: cada vez que vayas a hacer un bucle con append, párate un segundo y pregúntate si una comprehension lo expresa mejor. La mitad de las veces, sí.
Si quieres aprender Python desde la base con ejemplos prácticos como los de esta entrada — incluyendo bucles, listas, comprehensions, dict, sets y todo lo que necesitas para escribir código Python de verdad — te lo enseño paso a paso en El Pythonista.
Un abrazo,
Oscar
¿Quieres aprender Python en orden, no a saltos?
Esto que has leído es solo una pieza. En El Pythonista lo verás todo encadenado: 11 módulos, 37+ horas de vídeo, 734 actividades y un proyecto real (MovieTracker) que crece contigo desde la primera variable hasta el deploy a producción.
37+ horas · 734 actividades · Proyecto real · Acceso de por vida · 14 días de garantía
