La comprensión de listas (list comprehension) es una de las características más elegantes de Python. Te permite crear listas de manera concisa y eficiente en una sola línea de código. En esta guía aprenderás desde lo básico hasta técnicas avanzadas.

¿Qué es la Comprensión de Listas?

Una comprensión de listas es una forma compacta de crear listas basadas en secuencias existentes. Es la forma más Pythónica de transformar, filtrar y procesar datos.

El problema: Imagina que necesitas crear una lista con los cuadrados de los números del 1 al 10.

# Forma tradicional con bucle for
numeros_cuadrados = []
for numero in range(1, 11):
    numeros_cuadrados.append(numero ** 2)

print(numeros_cuadrados)  # Salida: [1, 4, 9, 16, 25, 36, 49, 64, 81, 100]

# Con list comprehension
numeros_cuadrados_comp = [numero ** 2 for numero in range(1, 11)]

print(numeros_cuadrados_comp)  # Salida: [1, 4, 9, 16, 25, 36, 49, 64, 81, 100]

La segunda versión es más clara, más legible y más eficiente en términos de rendimiento.

Sintaxis Básica

La estructura de una comprensión de listas sigue este patrón:

[expresion for elemento in iterable]

Veamos ejemplos prácticos:

# Crear una lista de números del 0 al 9
lista_numerica = [x for x in range(10)]
print(lista_numerica)  # [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

# Duplicar valores
valores_duplicados = [x * 2 for x in range(5)]
print(valores_duplicados)  # [0, 2, 4, 6, 8]

# Trabajar con cadenas
lista_frutas = ["manzana", "platano", "naranja"]
frutas_mayusculas = [fruta.upper() for fruta in lista_frutas]
print(frutas_mayusculas)  # ['MANZANA', 'PLATANO', 'NARANJA']

# Obtener longitudes de cadenas
longitudes = [len(fruta) for fruta in lista_frutas]
print(longitudes)  # [7, 7, 7]

# Operaciones matemáticas
temperaturas_celsius = [0, 10, 20, 30, 40]
temperaturas_fahrenheit = [(temp * 9/5) + 32 for temp in temperaturas_celsius]
print(temperaturas_fahrenheit)  # [32.0, 50.0, 68.0, 86.0, 104.0]

Si tienes dificultades con los conceptos de iteración, revisa nuestro tutorial sobre estructuras de control de Python.

Comprensión de Listas con Filtros

Puedes agregar condiciones para filtrar elementos durante la creación de la lista:

[expresion for elemento in iterable if condicion]

Ejemplos de Filtros

# Solo números pares
rango_numeros = range(20)
numeros_pares = [num for num in rango_numeros if num % 2 == 0]
print(numeros_pares)  # [0, 2, 4, 6, 8, 10, 12, 14, 16, 18]

# Solo números impares
numeros_impares = [num for num in rango_numeros if num % 2 != 0]
print(numeros_impares)  # [1, 3, 5, 7, 9, 11, 13, 15, 17, 19]

# Palabras con más de 3 letras
lista_palabras = ["Python", "es", "increible", "y", "poderoso"]
palabras_largas = [palabra for palabra in lista_palabras if len(palabra) > 3]
print(palabras_largas)  # ['Python', 'increible', 'poderoso']

# Valores positivos
valores_mixtos = [-5, -2, 0, 3, 7, -1, 10]
valores_positivos = [val for val in valores_mixtos if val > 0]
print(valores_positivos)  # [3, 7, 10]

# Nombres que empiezan con vocal
lista_nombres = ["Ana", "Bruno", "Isabella", "Carlos", "Eduardo"]
nombres_vocal = [nombre for nombre in lista_nombres if nombre[0].lower() in 'aeiou']
print(nombres_vocal)  # ['Ana', 'Isabella', 'Eduardo']

If-Else en Comprensiones

Para transformaciones condicionales, usa la sintaxis if-else antes del bucle for:

[expresion_si_verdadero if condicion else expresion_si_falso for elemento in iterable]

Ejemplos de Transformación

# Clasificar números como Pares o Impares
secuencia_numeros = [1, 2, 3, 4, 5, 6]
tipos_numeros = ["Par" if num % 2 == 0 else "Impar" for num in secuencia_numeros]
print(tipos_numeros)  # ['Impar', 'Par', 'Impar', 'Par', 'Impar', 'Par']

# Clasificar calificaciones
calificaciones_estudiantes = [8.5, 5.0, 7.5, 3.0, 9.0]
estado_aprobacion = ["Aprobado" if nota >= 7 else "Reprobado" for nota in calificaciones_estudiantes]
print(estado_aprobacion)  # ['Aprobado', 'Reprobado', 'Aprobado', 'Reprobado', 'Aprobado']

# Reemplazar valores nulos
datos_base_crudos = [10, None, 30, None, 50]
datos_limpiados = [val if val is not None else 0 for val in datos_base_crudos]
print(datos_limpiados)  # [10, 0, 30, 0, 50]

# Aplicar descuentos
precios_productos = [100, 200, 300, 400]
precios_descontados = [precio * 0.9 if precio > 200 else precio for precio in precios_productos]
print(precios_descontados)  # [100, 200, 270.0, 360.0]

Para profundizar en condicionales, consulta nuestra guía sobre estructuras condicionales de Python.

Comprensiones Anidadas

Puedes tener múltiples bucles for en una sola comprensión:

# Crear una matriz 3x3
matriz = [[i * 3 + j for j in range(1, 4)] for i in range(3)]
print(matriz)
# [[1, 2, 3],
#  [4, 5, 6],
#  [7, 8, 9]]

# Aplanar una lista de listas
lista_anidada = [[1, 2, 3], [4, 5], [6, 7, 8, 9]]
lista_aplanada = [elem for sublista in lista_anidada for elem in sublista]
print(lista_aplanada)  # [1, 2, 3, 4, 5, 6, 7, 8, 9]

# Combinaciones de productos
colores = ["rojo", "azul"]
tallas = ["S", "M", "L"]
productos = [f"{color}-{talla}" for color in colores for talla in tallas]
print(productos)
# ['rojo-S', 'rojo-M', 'rojo-L', 'azul-S', 'azul-M', 'azul-L']

# Coordenadas del tablero de ajedrez
tablero = [(x, y) for x in range(8) for y in range(8)]
print(f"Total de posiciones: {len(tablero)}")  # 64

Proyecto: Sistema de Calificaciones

Veamos un ejemplo que combina comprensiones de listas con funciones:

class SistemaCalificaciones:
    def __init__(self):
        self.estudiantes = [
            {"nombre": "Ana Silva", "calificaciones": [8.5, 9.0, 7.5]},
            {"nombre": "Bruno Costa", "calificaciones": [6.0, 5.5, 6.5]},
            {"nombre": "Carla Santos", "calificaciones": [9.5, 10.0, 9.0]},
            {"nombre": "Daniel Souza", "calificaciones": [4.0, 5.0, 3.5]},
            {"nombre": "Elena Oliveira", "calificaciones": [7.0, 8.0, 7.5]}
        ]

    def calcular_promedios(self):
        return [
            {
                "nombre": est["nombre"],
                "promedio": sum(est["calificaciones"]) / len(est["calificaciones"])
            }
            for est in self.estudiantes
        ]

    def estudiantes_aprobados(self, promedio_minimo=7.0):
        promedios = self.calcular_promedios()
        return [est["nombre"] for est in promedios if est["promedio"] >= promedio_minimo]

    def generar_reporte(self):
        promedios = self.calcular_promedios()
        reporte = [
            f"{est['nombre']}: {est['promedio']:.1f} - " +
            ("Aprobado" if est['promedio'] >= 7 else "Reprobado")
            for est in promedios
        ]
        return "\n".join(reporte)

sistema = SistemaCalificaciones()
print(sistema.generar_reporte())

Este tipo de proyecto es ideal para tu portafolio de Python.

Rendimiento: List Comprehension vs Bucles

Las comprensiones de listas son generalmente más rápidas que los bucles for tradicionales en Python:

import time

n = 1_000_000

# Bucle tradicional
inicio = time.time()
resultado_bucle = []
for i in range(n):
    resultado_bucle.append(i * 2)
tiempo_bucle = time.time() - inicio

# List comprehension
inicio = time.time()
resultado_comp = [i * 2 for i in range(n)]
tiempo_comp = time.time() - inicio

print(f"Bucle: {tiempo_bucle:.4f} segundos")
print(f"List comprehension: {tiempo_comp:.4f} segundos")

Set y Dict Comprehensions

Python también ofrece comprensiones similares para conjuntos y diccionarios:

Set Comprehension

# Eliminar duplicados
numeros = [1, 2, 2, 3, 3, 3, 4, 4, 5]
cuadrados_unicos = {x ** 2 for x in numeros}
print(carrados_unicos)  # {1, 4, 9, 16, 25}

# Letras únicas en mayúsculas
texto = "Python es increible"
letras = {c.upper() for c in texto if c.isalpha()}
print(letras)

Dict Comprehension

# Mapa de valores al cuadrado
diccionario_cuadrados = {num: num**2 for num in range(1, 6)}
print(diccionario_cuadrados)  # {1: 1, 2: 4, 3: 9, 4: 16, 5: 25}

# Invertir un diccionario
original = {"a": 1, "b": 2, "c": 3}
invertido = {v: k for k, v in original.items()}
print(invertido)  # {1: 'a', 2: 'b', 3: 'c'}

Cuándo NO Usar List Comprehension

Las comprensiones de listas no siempre son la mejor opción:

  • Lógica muy compleja: Si tu lógica requiere muchas líneas, usa un bucle estándar.
  • Efectos secundarios: Como imprimir en consola, guardar archivos o modificar variables externas.
  • Múltiples operaciones independientes: Cuando cada elemento requiere varias transformaciones.
  • Depuración: Los bucles tradicionales son más fáciles de depurar.

Próximos Pasos

Ahora que dominas las comprensiones de listas, continúa tu aprendizaje en Python explorando: