Contenido del curso
Fundamentos de Python
Los fundamentos de Python incluyen la sintaxis (sangría para bloques de código), los tipos de datos básicos (numéricos, booleanos, cadenas de texto), las variables, el control de flujo (condicionales como if/elif/else y bucles como for/while), y las funciones (bloques de código reutilizables).
0/6
Operadores y Control de Flujo
Los operadores en Python se clasifican en varios tipos (aritméticos, de comparación, lógicos, de asignación, etc.), mientras que el control de flujo se refiere al orden en que se ejecutan las instrucciones, modificándolo con estructuras como if, elif, else (condicionales), y for o while (bucles). Las instrucciones break, continue y pass también controlan el flujo dentro de los bucles.
0/3
Funciones y Manejo de Errores
Las funciones en Python son bloques de código reutilizables, mientras que el manejo de errores (excepciones) se hace con los bloques try, except, else y finally para gestionar errores de ejecución y evitar que el programa se detenga abruptamente. try ejecuta un código, except lo captura si ocurre un error específico, else se ejecuta si no hay error y finally se ejecuta siempre, haya o no error.
0/3
Estructuras de Datos
Las estructuras de datos principales en Python son las listas, tuplas, diccionarios y conjuntos. Estos tipos de datos se diferencian por su mutabilidad (si sus elementos se pueden cambiar después de su creación) y si mantienen el orden de los elementos. Las listas son ordenadas y mutables, mientras que las tuplas son ordenadas e inmutables. Los diccionarios son colecciones no ordenadas de pares clave-valor, y los conjuntos son colecciones desordenadas de elementos únicos.
0/5
Programación Orientada a Objetos (POO)
La Programación Orientada a Objetos (POO) en Python es un paradigma que organiza el código en torno a objetos, que son instancias de clases. Las clases actúan como plantillas que definen los atributos (datos) y métodos (comportamientos) de los objetos, permitiendo crear programas más modularizados, reutilizables y fáciles de mantener. Python soporta conceptos clave de la POO como la herencia, el encapsulamiento y el polimorfismo.
0/5
Ambientes virtuales
Un entorno virtual de Python es un espacio aislado que permite instalar paquetes y dependencias específicos para un proyecto concreto sin afectar a otras aplicaciones o a la instalación global de Python. Se crea una carpeta con una instalación de Python y una copia local de pip dentro de este entorno, lo que permite a cada proyecto tener sus propias bibliotecas y versiones, evitando así conflictos entre diferentes proyectos que puedan requerir versiones distintas de la misma librería.
0/1
Archivos
El manejo de archivos en Python se realiza principalmente usando la función open() para abrir un archivo y los métodos read(), write(), append() y close() para manipularlo. Es crucial gestionar los archivos adecuadamente, cerrándolos para liberar recursos, aunque es más recomendable usar la sentencia with, que cierra el archivo automáticamente. Python permite trabajar con archivos de texto y binarios, así como con distintos modos de apertura como 'r' (solo lectura), 'w' (escritura/sobreescritura), y 'a' (añadir).
0/1
Módulos y Librerías Estándar
Un "módulo" en Python se refiere a dos conceptos distintos: un archivo .py con código que se puede importar para reutilizar funciones, clases y variables, y el operador % que calcula el residuo de una división entera. Ambos son útiles para organizar el código y resolver problemas matemáticos, respectivamente.
0/2
Hilos y tareas en Python
En Python, los hilos (threads) son secuencias de ejecución dentro de un proceso que permiten la concurrencia, ejecutando tareas simultáneamente para aprovechar mejor los recursos del sistema. Las tareas son las unidades de trabajo a realizar, como descargar archivos o procesar datos. Se utilizan para manejar operaciones que implican espera (I/O-bound) de forma eficiente, permitiendo que una aplicación no se bloquee mientras espera. Para ello, se usa el módulo threading, se crean objetos Thread que representan las tareas, se inician con .start() y se pueden sincronizar con mecanismos como Lock para evitar conflictos.
0/1
Curso de Programación en Pythón 3.

    📘 Lección 4.5 — Comprehensions en Python

    1. Parte 1 — Introducción a las Comprehensions y List Comprehensions
    2. Parte 2 — Dict Comprehensions (diccionarios)
    3. Parte 3 — Set Comprehensions (conjuntos)
    4. Parte 4 — Condicionales en Comprehensions
    5. Parte 5 — Comprehensions anidadas, rendimiento y optimización

    Haz clic en cada parte para navegar directamente. Cada sección está diseñada para estudiantes principiantes, con ejemplos visuales, código comentado y comparaciones con bucles tradicionales.

    Parte 1 — Introducción a las Comprehensions y List Comprehensions

    Objetivo: entender qué son las comprensiones (comprehensions) en Python, por qué simplifican el código y cómo crear listas de forma elegante, legible y eficiente.


    1) ¿Qué son las comprehensions?

    Las comprehensions (comprensiones) son una forma concisa y expresiva de crear estructuras de datos como listas, diccionarios o conjuntos directamente a partir de iterables.

    Permiten reemplazar bucles for y condicionales if sencillos con una sola línea legible, manteniendo la semántica pero mejorando el rendimiento y la claridad.

    # Sin comprehension:
    cuadrados = []
    for n in range(5):
        cuadrados.append(n ** 2)
    
    # Con list comprehension:
    cuadrados = [n ** 2 for n in range(5)]
    print(cuadrados)  # [0, 1, 4, 9, 16]
    

    Ambas versiones hacen lo mismo, pero la comprensión reduce el código en más del 60%, mejora la legibilidad y elimina la necesidad de llamar a append() explícitamente.

    Idea clave: una comprensión es un generador de colecciones expresado dentro de la propia estructura: [expresión for elemento in iterable].

    2) Estructura general de una List Comprehension

    La sintaxis básica de una comprensión de lista es:

    [expresión for elemento in iterable]

    Donde:

    ComponenteDescripciónEjemplo
    expresiónTransformación o valor que se añade a la lista.n ** 2
    elementoVariable que toma cada valor del iterable.n
    iterableCualquier objeto que se pueda recorrer con for (lista, rango, cadena, etc.).range(5)

    En otras palabras, Python itera sobre iterable, aplica la expresión a cada elemento y agrega el resultado a la nueva lista.

    # Crear una lista de cubos
    cubos = [n ** 3 for n in range(1, 6)]
    print(cubos)  # [1, 8, 27, 64, 125]
    

    3) Comparación entre bucle tradicional y comprensión

    Versión tradicionalVersión con comprensión
    resultado = []
    for x in range(10):
        resultado.append(x * 2)
    print(resultado)
    resultado = [x * 2 for x in range(10)]
    print(resultado)

    Ambas generan la lista [0, 2, 4, 6, 8, 10, 12, 14, 16, 18], pero la segunda es más legible, idiomática y pythonic.

    Pythonic significa “escrito al estilo natural de Python”: legible, expresivo y conciso.

    4) Ejemplos comunes de List Comprehensions

    4.1 Generar listas numéricas

    # Lista de los primeros 10 números pares
    pares = [n for n in range(20) if n % 2 == 0]
    print(pares)  # [0, 2, 4, 6, 8, 10, 12, 14, 16, 18]
    

    4.2 Convertir cadenas a mayúsculas

    nombres = ["ana", "carlos", "elena"]
    nombres_mayus = [nombre.upper() for nombre in nombres]
    print(nombres_mayus)  # ['ANA', 'CARLOS', 'ELENA']
    

    4.3 Calcular longitudes de palabras

    palabras = ["python", "código", "abierto"]
    longitudes = [len(p) for p in palabras]
    print(longitudes)  # [6, 6, 7]
    

    4.4 Filtrar con condicional

    # Números divisibles entre 3
    div_3 = [n for n in range(1, 20) if n % 3 == 0]
    print(div_3)  # [3, 6, 9, 12, 15, 18]
    

    4.5 Transformar con expresiones más complejas

    # Elevar al cuadrado los números impares
    impares_cuadrado = [n ** 2 for n in range(10) if n % 2 != 0]
    print(impares_cuadrado)  # [1, 9, 25, 49, 81]
    

    5) Ventajas de usar comprehensions

    VentajaDescripción
    ConcisiónReemplazan varios renglones de código con una sola línea.
    ClaridadExpresan directamente la intención: “quiero una lista de esto, a partir de esto”.
    RendimientoSon más rápidas que los bucles for convencionales al evitar múltiples llamadas a append().
    PythonicidadEs la forma idiomática recomendada por la comunidad y el Zen de Python (“Beautiful is better than ugly”).

    6) Mini ejercicios prácticos

    1. Crea una lista con los cuadrados de los números del 1 al 10.
      cuadrados = [n ** 2 for n in range(1, 11)]
      print(cuadrados)
    2. Genera una lista con los caracteres de una cadena en mayúsculas.
      texto = "python"
      letras = 
      print(letras)
    3. Obtén una lista de los múltiplos de 5 entre 1 y 50.
      multiplos_5 = [n for n in range(1, 51) if n % 5 == 0]
      print(multiplos_5)

    7) Resumen ejecutivo

    • Las comprehensions son expresiones concisas para crear listas, diccionarios o conjuntos.
    • La estructura base es [expresión for elemento in iterable].
    • Pueden incluir condicionales y anidamientos.
    • Son más legibles, rápidas y “pythónicas”.
    • Perfectas para reemplazar bucles simples que construyen listas.
    En la Parte 2 aprenderás las Dict Comprehensions, que permiten generar diccionarios dinámicamente a partir de iterables, con claves y valores definidos en una sola expresión.

    Parte 2 — Dict Comprehensions (diccionarios)

    Objetivo: aprender a generar diccionarios en una sola línea utilizando comprensiones, creando pares clave–valor a partir de datos iterables o transformaciones.


    1) Introducción a las Dict Comprehensions

    Una Dict Comprehension (comprensión de diccionario) es una construcción sintáctica de Python que permite crear un diccionario
    en una sola línea, de forma similar a las List Comprehensions, pero generando pares clave:valor.

    Su estructura general es:

    {clave: valor for elemento in iterable}

    Python recorre el iterable, evalúa la expresión de clave y valor para cada elemento y construye un diccionario con ellos.

    # Ejemplo básico: crear un diccionario con los cuadrados de 1 a 5
    cuadrados = {n: n**2 for n in range(1, 6)}
    print(cuadrados)
    # {1: 1, 2: 4, 3: 9, 4: 16, 5: 25}
    
    Idea clave: en una Dict Comprehension, cada elemento genera una pareja clave:valor, y las claves deben ser únicas.

    2) Comparación: bucle tradicional vs Dict Comprehension

    Versión tradicionalDict Comprehension
    cuadrados = {}
    for n in range(1, 6):
        cuadrados[n] = n ** 2
    print(cuadrados)
    cuadrados = {n: n ** 2 for n in range(1, 6)}
    print(cuadrados)

    La segunda versión es más legible, elimina la necesidad de inicializar el diccionario y evita el uso explícito de .update() o [].


    3) Aplicaciones comunes de Dict Comprehensions

    3.1 Invertir claves y valores

    # Intercambiar claves y valores en un diccionario
    monedas = {"USD": "Dólar", "EUR": "Euro", "JPY": "Yen"}
    invertido = {valor: clave for clave, valor in monedas.items()}
    print(invertido)
    # {'Dólar': 'USD', 'Euro': 'EUR', 'Yen': 'JPY'}
    

    Útil para: búsquedas inversas o intercambio de roles entre clave–valor.

    3.2 Transformar valores

    precios_usd = {"manzana": 1, "banana": 0.5, "pera": 0.75}
    # Convertir precios a euros
    precios_eur = {fruta: precio * 0.9 for fruta, precio in precios_usd.items()}
    print(precios_eur)
    # {'manzana': 0.9, 'banana': 0.45, 'pera': 0.675}
    

    3.3 Filtrar datos en el diccionario

    # Filtrar solo frutas con precio > 0.6
    caro = {f: p for f, p in precios_usd.items() if p > 0.6}
    print(caro)
    # {'manzana': 1, 'pera': 0.75}
    

    Puedes incluir condicionales al final (al igual que en las list comprehensions) para filtrar los elementos que serán incluidos.


    4) Dict Comprehensions a partir de otras estructuras

    También puedes generar diccionarios desde listas, tuplas o cualquier iterable. Esto resulta muy útil para transformar datos.

    # Crear un diccionario a partir de dos listas paralelas
    claves = ["nombre", "edad", "ciudad"]
    valores = ["Ana", 25, "Madrid"]
    
    persona = {k: v for k, v in zip(claves, valores)}
    print(persona)
    # {'nombre': 'Ana', 'edad': 25, 'ciudad': 'Madrid'}
    

    La función zip() combina elementos de ambas listas, y la comprensión construye el diccionario clave–valor automáticamente.


    5) Ejemplos prácticos

    5.1 Crear un diccionario de longitudes de palabras

    palabras = ["python", "comprehension", "código", "curso"]
    longitudes = {p: len(p) for p in palabras}
    print(longitudes)
    # {'python': 6, 'comprehension': 13, 'código': 6, 'curso': 5}
    

    5.2 Generar un diccionario de números y su paridad

    paridad = {n: ("par" if n % 2 == 0 else "impar") for n in range(1, 6)}
    print(paridad)
    # {1: 'impar', 2: 'par', 3: 'impar', 4: 'par', 5: 'impar'}
    

    5.3 Normalizar texto en claves

    # Normalizar claves a minúsculas
    datos = {"Nombre": "Ana", "Ciudad": "Madrid", "PAÍS": "España"}
    normalizado = {k.lower(): v for k, v in datos.items()}
    print(normalizado)
    # {'nombre': 'Ana', 'ciudad': 'Madrid', 'país': 'España'}
    

    6) Tabla resumen de sintaxis

    PatrónDescripciónEjemplo
    {k:v for k,v in iterable}Básico: crea pares clave–valor.{x:x**2 for x in range(5)}
    {k:v for k,v in iterable if cond}Incluye solo los elementos que cumplen la condición.{f:p for f,p in precios if p>1}
    {exp1:exp2 for ...}Permite expresiones complejas para transformar.{k.upper():v*2 for k,v in d.items()}

    7) Ejercicios prácticos

    1. Crea un diccionario con los números del 1 al 5 como claves y sus cubos como valores.
      cubos = {n: n**3 for n in range(1, 6)}
      print(cubos)
    2. A partir de una lista de nombres, crea un diccionario que mapee cada nombre con su longitud.
      nombres = ["Ana", "Carlos", "Beatriz"]
      longitudes = {n: len(n) for n in nombres}
      print(longitudes)
    3. Dado un diccionario de temperaturas en °C, genera otro en °F.
      celsius = {"Madrid": 20, "Sevilla": 30, "Bilbao": 18}
      fahrenheit = {ciudad: (temp * 9/5) + 32 for ciudad, temp in celsius.items()}
      print(fahrenheit)

    8) Resumen ejecutivo

    • Las Dict Comprehensions crean diccionarios con una sola expresión: {clave: valor for ...}.
    • Pueden incluir condicionales, expresiones y funciones.
    • Evitan bucles largos y mejoran la legibilidad del código.
    • Se pueden combinar con zip() o .items() para transformar datos fácilmente.
    En la Parte 3 aprenderás las Set Comprehensions, ideales para crear conjuntos únicos y eliminar duplicados con una sintaxis igual de compacta.

    Parte 3 — Set Comprehensions (conjuntos)

    Objetivo: crear set (conjuntos) en una sola línea para eliminar duplicados, filtrar y transformar datos con sintaxis concisa y rendimiento sólido.


    1) ¿Qué es una Set Comprehension?

    Una Set Comprehension genera un set aplicando una expresión a cada elemento de un iterable.
    Al ser conjuntos, los resultados son únicos y el contenedor no garantiza orden. Es perfecta para
    deduplicar a la vez que transformas/filtras.

    # Bucle tradicional
    cuadrados = set()
    for n in range(5):
        cuadrados.add(n ** 2)
    
    # Set comprehension (equivalente y más concisa)
    cuadrados = {n ** 2 for n in range(5)}
    print(cuadrados)  # {0, 1, 4, 9, 16}
    Idea clave: usa {expresión for elemento in iterable} para producir un conjunto único sin duplicados.

    2) Sintaxis básica y con condición

    2.1 Forma base

    {expresion for item in iterable}

    2.2 Con filtrado (if)

    {expresion for item in iterable if condicion}
    # Cuadrados de los pares entre 0 y 9
    pares_cuadrados = {n ** 2 for n in range(10) if n % 2 == 0}
    print(pares_cuadrados)  # {0, 4, 16, 36, 64}

    Patrón idéntico al mostrado en list comprehensions, pero el resultado es un set.


    3) Casos de uso típicos

    3.1 Deduplicar mientras transformas

    # Eliminar duplicados y quedarnos con primeras letras únicas
    palabras = ["manzana", "banana", "mango", "melón", "mora", "naranja"]
    primeras = {p[0] for p in palabras}
    print(primeras)  # {'m', 'b', 'n'}

    Útil cuando te interesa el conjunto de valores sin repeticiones.

    3.2 Filtrado de datos únicos

    # Vocales únicas presentes en un texto
    texto = "python es un lenguaje de programación versátil"
    vocales = {c for c in texto.lower() if c in "aeiou"}
    print(vocales)  # {'a', 'e', 'i', 'o', 'u'}

    3.3 Transformación rápida con eliminación de duplicados

    # Longitudes únicas de palabras
    palabras = ["casa", "perro", "sol", "luna", "mar", "montaña"]
    longitudes_unicas = {len(p) for p in palabras}
    print(longitudes_unicas)  # {3, 4, 5, 7}

    3.4 Operaciones sobre conjuntos (combinación)

    A = {1, 2, 3, 4, 5}
    B = {4, 5, 6, 7, 8}
    
    # Duplicar elementos de la unión
    union_doble = {x * 2 for x in A.union(B)}
    print(union_doble)  # {2, 4, 6, 8, 10, 12, 14, 16}
    
    # Elevar al cuadrado elementos de la intersección
    intersec_cuad = {x ** 2 for x in A.intersection(B)}
    print(intersec_cuad)  # {16, 25}

    Puedes mezclar comprehensions con métodos/operadores de conjuntos sin problema.


    4) Notas importantes (orden, hashabilidad y pertenencia)

    • Sin orden ni índice: un set no mantiene orden; si necesitas orden estable, usa list comprehension y ordena después.
    • Elementos hashables: solo tipos inmutables (números, str, tuplas…); listas o dicts darán TypeError.
    • Búsquedas rápidas: comprobar pertenencia x in s es muy eficiente, ideal para filtros y deduplicación.
    # Mantener orden y eliminar duplicados (truco complementario si luego quieres lista ordenable)
    numeros = [5, 2, 3, 1, 4, 3]
    sin_dupes_preservando_orden = list(dict.fromkeys(numeros))
    print(sin_dupes_preservando_orden)  # [5, 2, 3, 1, 4]

    5) Mini casos reales

    5.1 Productos únicos comprados

    compras = [
        {"cliente": "Ana", "producto": "laptop"},
        {"cliente": "Juan", "producto": "teléfono"},
        {"cliente": "Ana", "producto": "auriculares"},
        {"cliente": "Pedro", "producto": "laptop"},
        {"cliente": "Juan", "producto": "auriculares"},
        {"cliente": "Ana", "producto": "teléfono"},
    ]
    productos_unicos = {c["producto"] for c in compras}
    print(productos_unicos)  # {'laptop', 'teléfono', 'auriculares'}

    5.2 Clientes que compraron un producto

    compradores_laptop = {c["cliente"] for c in compras if c["producto"] == "laptop"}
    print(compradores_laptop)  # {'Ana', 'Pedro'}

    5.3 Iniciales únicas de clientes

    iniciales = {c["cliente"][0] for c in compras}
    print(iniciales)  # {'A', 'J', 'P'}

    Estos patrones vienen tal cual de tu referencia sobre set comprehensions.


    6) Rendimiento y cuándo usarlas

    • Al crear conjuntos, las comprehensions son concisas y suelen ser eficientes frente a bucles con add() por iteración.
    • Son idóneas si necesitas a la vez transformar y quitar duplicados.
    • Si el conjunto resultante va a ser muy grande y solo quieres iterar por él una vez, considera un generador antes de convertir a set (para escalabilidad).
    Regla de oro: si necesitas unicidad + transformación simple, usa set comprehension. Si además te importa el orden estable, usa list comprehension y deduplica con un truco de diccionario antes/ después.

    7) Tabla rápida de sintaxis

    PatrónQué haceEjemplo
    {exp for x in it}Crea un set transformando cada elemento.{x*x for x in range(5)}
    {exp for x in it if cond}Filtra con condición.{x for x in nums if x%2==0}
    {f(y) for y in A|B}Combina con operaciones de conjuntos.{y*2 for y in A.union(B)}

    8) Mini-retos (5′)

    1. Extrae las vocales únicas de "Aprender Python es divertido" (en minúscula).
      texto = "Aprender Python es divertido"
      vocales = {c for c in texto.lower() if c in "aeiou"}
      print(vocales)
    2. Crea un set con los cuadrados únicos de los números entre 1 y 30 que sean múltiplos de 3.
      cuadrados = {n**2 for n in range(1,31) if n % 3 == 0}
      print(cuadrados)
    3. Dadas palabras con repeticiones, obtén las longitudes únicas de las que empiezan por “p”.
      palabras = ["python","poema","playa","python","piedra","sol"]
      lens_p = {len(p) for p in palabras if p.startswith("p")}
      print(lens_p)

    9) Resumen ejecutivo

    • Set comprehension: {exp for item in iterable [if cond]}.
    • Ideal para unicidad + transformación/filtrado en una pasada.
    • Sin orden ni índice; elementos deben ser hashables.
    • Se integra de forma natural con operaciones de conjuntos (union, intersection…).
    En la Parte 4 veremos Condicionales en comprehensions (if/else en la expresión, múltiples condiciones y patrones anti-boilerplate) con comparativas de legibilidad y rendimiento.

    Parte 4 — Condicionales en Comprehensions

    Objetivo: dominar el uso de condiciones dentro de list/dict/set comprehensions para filtrar y transformar datos de forma limpia, legible y eficiente.


    1) Dos modos de “meter lógica” en una comprehension

    Hay dos ubicaciones con propósitos distintos:

    1. Filtro (después del for): incluye o excluye elementos.
      [exp for x in it <u>if cond(x)</u>]
    2. Condicional en la expresión (ternario): elige el valor que se agrega.
      [<u>exp_true if cond(x) else exp_false</u> for x in it]
    Regla mental: después del for filtras; antes del for (en la “expresión”) decides qué valor producir.

    2) Filtro con if (al final)

    Sirve para seleccionar los elementos que entran en el resultado.

    # Números pares entre 0 y 9 (solo se incluyen los que cumplen)
    pares = [n for n in range(10) if n % 2 == 0]
    print(pares)  # [0, 2, 4, 6, 8]

    Este patrón existe por igual para list, dict y set comprehensions y es central en tu referencia.

    ColecciónPatrón de filtroEjemplo
    Lista[exp for x in it if cond][w.upper() for w in palabras if w.isalpha()]
    Set{exp for x in it if cond}{len(w) for w in palabras if w.startswith("p")}
    Dict{k:v for k,v in it if cond}{k:v for k,v in d.items() if v > 0}

    3) Condicional ternario en la expresión (A if cond else B)

    Se usa para elegir el valor que se va a producir por elemento (no para filtrar).

    # Etiqueta "par"/"impar" para números 1..6 (nadie se filtra)
    paridad = ["par" if n % 2 == 0 else "impar" for n in range(1, 7)]
    print(paridad)  # ['impar','par','impar','par','impar','par']
    # Dict comprehension con ternario en el valor
    precios = {"manzana": 1.0, "banana": 0.5, "pera": 1.2}
    clasif = {f: ("caro" if p >= 1.0 else "barato") for f, p in precios.items()}
    print(clasif)  # {'manzana': 'caro', 'banana': 'barato', 'pera': 'caro'}

    Tu PDF muestra este uso como forma idiomática de transformar valores según condiciones simples.


    4) Múltiples condiciones y composición

    4.1 Encadenar filtros

    # Pares mayores que 10
    resultado = [n for n in range(30) if n % 2 == 0 if n > 10]
    print(resultado)  # [12, 14, 16, 18, 20, 22, 24, 26, 28]

    4.2 Condiciones compuestas (and/or)

    # Múltiplos de 3 o 5, pero no de ambos
    nums = [n for n in range(1, 50) if (n % 3 == 0) ^ (n % 5 == 0)]
    print(nums)

    4.3 Ternario + filtro

    # Formatear números >= 1000 con separador; descartar negativos
    datos = ["{:,}".format(n) if n >= 1000 else str(n) 
             for n in [1200, 50, -3, 5_000, 999] 
             if n >= 0]
    print(datos)  # ['1,200', '50', '5,000', '999']
    Lectibilidad > malabares: tu referencia recomienda mantener las condiciones simples y preferir bucles tradicionales si la lógica se complica.

    5) Casos prácticos (list/dict/set)

    5.1 Limpieza básica de texto (list)

    # Mantener palabras alfanuméricas y normalizarlas
    texto = "Python, es #genial y muy versátil!"
    tokens = [w.lower() for w in texto.replace(",", "").split() if w.isalpha() or w.isalnum()]
    print(tokens)

    5.2 Filtrado de inventario (dict)

    stock = {"manzanas": 12, "plátanos": 0, "naranjas": 25, "peras": 3}
    disponibles = {k: v for k, v in stock.items() if v > 0}
    print(disponibles)  # {'manzanas': 12, 'naranjas': 25, 'peras': 3}

    5.3 Vocales únicas en una frase (set)

    frase = "python es un lenguaje de programación versátil"
    vocales = {c for c in frase.lower() if c in "aeiou"}
    print(vocales)  # {'a', 'e', 'i', 'o', 'u'}

    Estos patrones (filtrado y extracción) están alineados con los casos de uso del PDF.


    6) Antipatrones y cómo evitarlos

    • Comprehensions kilométricas: si hay demasiadas condiciones/ternarios, pasa a un for normal con if anidados. Legibilidad primero.
    • Trabajo pesado en la condición: evita recomputar funciones caras dentro del if; guarda en variables previas o usa funciones auxiliares.
    • Abusar del ternario: uno anidado es tolerable; múltiples ternarios → refactoriza.
    • Orden en set comprehensions: no confíes en él; si importa, usa lista + sorted().

    7) Rendimiento y memoria (quick wins)

    • Las comprehensions suelen ser más rápidas que los bucles con append/add/asignación por su implementación interna y menor sobrecarga.
    • Para colecciones muy grandes donde solo necesitas iterar una vez, considera generadores ((exp for x in it)) y convertir a lista/set más tarde.
    • Filtrar primero, transformar después: a menudo es más barato (menos evaluaciones de la expresión de salida).
    # Generador + conversión tardía (memoria-friendly)
    gen = (n for n in range(1_000_000) if n % 10 == 0)
    muestra = list(next(gen) for _ in range(5))  # consumir poco a poco
    print(muestra)

    8) Micro-retos (5′)

    1. Genera ["PAR", "IMPAR", ...] para 1..12 (sin filtrar, usa ternario).
      etq = ["PAR" if n % 2 == 0 else "IMPAR" for n in range(1, 13)]
      print(etq)
    2. De una lista de tuplas (nombre, edad), arma un dict solo con mayores de 18.
      personas = [("Ana", 17), ("Carlos", 21), ("Elena", 19)]
      mayores = {n: e for (n, e) in personas if e >= 18}
      print(mayores)
    3. Extrae un set con longitudes únicas de palabras que empiecen por “a” u “o”.
      palabras = ["agua", "oso", "python", "ala", "sol", "ola"]
      lens_unicas = {len(p) for p in palabras if p[0] in {"a","o"}}
      print(lens_unicas)

    9) Resumen ejecutivo

    • Filtro: ... for x in it if cond incluye/excluye elementos.
    • Ternario: exp_true if cond else exp_false decide el valor que se añade.
    • Combínalos con moderación; si la lógica crece, cambia a bucles claros.
    • Aplica generadores cuando el volumen de datos sea enorme.
    En la Parte 5 cerraremos con comprensiones anidadas, patrones de optimización y casos “pro” (matrices, flattening, productos cartesianos) con guía de legibilidad y rendimiento.

    Parte 5 — Comprensiones anidadas y optimización

    Objetivo: dominar comprensiones anidadas (listas, diccionarios y conjuntos), aplicarlas a casos reales (matrices, flatten, producto cartesiano) y optimizarlas sin sacrificar legibilidad.


    1) Comprensiones anidadas: la base

    Una comprensión anidada usa varios for (y opcionalmente condiciones) dentro de la misma expresión. Útil para transformar estructuras 2D, generar combinaciones, o aplanar colecciones. Mantén la lógica simple para no perder legibilidad.

    # Lista de pares (i, j) con i in [0..2], j in [0..2]
    pares = [(i, j) for i in range(3) for j in range(3)]
    print(pares)  # [(0,0),(0,1),(0,2),(1,0)...]
    Regla de oro: de dentro hacia fuera, lee: “por cada i en range(3), por cada j en range(3), produce (i, j)”. Si la lectura cuesta, rompe en pasos.

    2) Flatten (aplanar listas de listas)

    Patrón clásico para pasar de 2D → 1D. Si la estructura es muy profunda o la lógica compleja, alterna con funciones auxiliares.

    matriz = [[1, 2, 3], [4, 5], [6]]
    aplanado = [x for fila in matriz for x in fila]
    print(aplanado)  # [1,2,3,4,5,6]

    Con condición (solo pares):

    aplanado_pares = [x for fila in matriz for x in fila if x % 2 == 0]
    print(aplanado_pares)  # [2, 4, 6]

    3) Matrices: mapeos y transposición

    Transforma cada celda con una expresión, o transpón una matriz con zip + comprensión.

    # Incrementar cada celda
    M = [[1, 2], [3, 4]]
    M_inc = [ for fila in M]
    print(M_inc)  # [[2,3],[4,5]]
    
    # Transponer (columnas<->filas)
    M_T = [ for col in zip(*M)]
    print(M_T)  # [[1,3],[2,4]]
    Legibilidad first: si la transformación por celda supera 1–2 operaciones, extrae una función transform(c) y úsala dentro de la comprensión.

    4) Producto cartesiano y combinaciones

    Genera combinaciones ordenadas entre dos colecciones, aplicando filtros in-line si procede.

    tallas = ["S", "M", "L"]
    colores = ["rojo", "azul"]
    combos = [(t, c) for t in tallas for c in colores]
    print(combos)  # [('S','rojo'),('S','azul'),('M','rojo'),...]
    # Filtrar al vuelo
    combos_filtrados = [(t, c) for t in tallas for c in colores if not (t == "S" and c == "rojo")]

    5) Dict y Set comprehensions anidadas

    También puedes anidar en diccionarios y conjuntos. Útil para indexar, agrupar o deduplicar con transformación.

    5.1 Índice invertido simple (dict)

    docs = [
        {"id": 1, "tags": ["python", "linux"]},
        {"id": 2, "tags": ["python", "datos"]},
    ]
    indice = {tag: {d["id"] for d in docs if tag in d["tags"]}
              for tag in {t for d in docs for t in d["tags"]}}
    print(indice)  # {'linux':{1}, 'python':{1,2}, 'datos':{2}}

    5.2 Diccionario a partir de pares (clave única + transformación)

    pares = [("ana", 8.5), ("carlos", 7.2), ("ana", 9.0)]
    # Último valor gana si hay claves duplicadas (propio de dict)
    notas = {k: v for (k, v) in pares}
    print(notas)  # {'ana': 9.0, 'carlos': 7.2}

    5.3 Set anidado: longitudes únicas por inicial

    palabras = ["perro","piedra","gato","guitarra","piano"]
    longitudes_por_inicial = {
        inicial: {len(w) for w in palabras if w.startswith(inicial)}
        for inicial in {w[0] for w in palabras}
    }
    print(longitudes_por_inicial)  # {'p':{5,6}, 'g':{4,8}}

    6) Condicionales en comprensiones anidadas

    Combina filtro y ternario de forma controlada. Si la expresión se vuelve densa, usa funciones auxiliares o bucles.

    # Etiquetar celdas >=10 como "OK", descartar negativas
    mat = [[-1, 5, 12], [0, 14, 3]]
    etiquetas = [["OK" if c >= 10 else "LOW" for c in fila if c >= 0] for fila in mat]
    print(etiquetas)  # [['LOW','OK'], ['LOW','OK','LOW']]
    Anti-patrón: más de dos for + varias condiciones + ternarios anidados = deuda técnica. Prioriza claridad; el PDF recomienda simplicidad y buen juicio.

    7) Optimización: performance y memoria

    • Comprehension vs bucle: suelen ser más rápidas que bucles con append()/add() por menor sobrecarga de Python.
    • Generadores: para flujos muy grandes, usa generator expressions y materializa al final si necesitas lista/set.
    • Filtra pronto: coloca el if de filtro lo antes posible; reduces trabajo aguas abajo.
    • Evita recomputar: factoriza cálculos costosos en variables o funciones auxiliares fuera de la comprensión.
    • Uso de zip/dict.fromkeys: resuelven casos comunes de unión/deduplicación con coste bajo y buen estilo.
    # Generador + materialización tardía
    gen = (n*n for n in range(1_000_000) if n % 10 == 0)  # memoria O(1)
    top5 = [next(gen) for _ in range(5)]
    print(top5)

    8) Tabla de patrones (cheatsheet)

    PatrónQué resuelveEjemplo
    [x for fila in M for x in fila]Flatten 2D → 1Daplanado = [x for f in M for x in f]
    [[f(c) for c in fila] for fila in M]Mapeo celda a celdaM2 = [ for fila in M]
    [(a,b) for a in A for b in B]Producto cartesianopairs = [(t,c) for t in T for c in C]
    {k: f(v) for k,v in d.items() if cond(v)}Filtrar + transformar dictcaro = {k:p for k,p in d.items() if p>1}
    {g(x) for x in it if cond(x)}Set único transformadolens = {len(w) for w in palabras}

    9) Ejercicios (evaluación rápida)

    1. Flatten + filtro: dada M = [[1, -3, 4], [0, 7], [-2, 5]], crea una lista con los positivos, en orden, elevados al cuadrado.
      Solución
      M = [[1, -3, 4], [0, 7], [-2, 5]]
      res = [x*x for fila in M for x in fila if x > 0]
      print(res)  # [1,16,7*7,25]
    2. Transposición limpia: transpón M = [[1,2,3],[4,5,6]] con zip + comprensión.
      Solución
      M = [[1,2,3],[4,5,6]]
      M_T = [ for col in zip(*M)]
      print(M_T)  # [[1,4],[2,5],[3,6]]
    3. Dict de conteo por inicial: de ["Ana","Alba","Luis","Lucía","Leo"], crea {"A":2, "L":3} usando dos comprensiones.
      Solución
      nombres = ["Ana","Alba","Luis","Lucía","Leo"]
      iniciales = {n[0] for n in nombres}
      conteo = {i: sum(1 for n in nombres if n.startswith(i)) for i in iniciales}
      print(conteo)  # {'A':2, 'L':3}
    4. Producto cartesiano filtrado: de tallas S,M,L y colores rojo, azul, verde, excluye ("S","rojo").
      Solución
      T, C = ["S","M","L"], ["rojo","azul","verde"]
      combos = [(t,c) for t in T for c in C if not (t=="S" and c=="rojo")]
      print(combos)
    5. Set anidado por categoría: a partir de [("dev","python"),("dev","linux"),("data","python")] genera {"dev":{"python","linux"}, "data":{"python"}}.
      Solución
      pares = [("dev","python"),("dev","linux"),("data","python")]
      cats = {cat for (cat, _) in pares}
      resultado = {cat: {tech for (c, tech) in pares if c == cat} for cat in cats}
      print(resultado)

    10) Resumen ejecutivo

    • Comprensiones anidadas: poderosas para 2D/3D, flatten y combinaciones; mantén la lógica simple.
    • Optimiza con generadores, filtra pronto y evita recomputaciones caras.
    • Si la expresión se vuelve densa, refactoriza a funciones o bucles claros: legibilidad > cleverness.
    Lección 4.5 completada end-to-end.
    Nuestra puntuación
    ¡Haz clic para puntuar esta entrada!
    (Votos: 0 Promedio: 0)
    Scroll al inicio