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.

    📘 4.2 Tuplas (tuple)

    Aprende qué son las tuplas en Python, su inmutabilidad, cómo aprovechar su rendimiento y
    las técnicas modernas de desempaquetado y conversión.

    1. Parte 1 — Inmutabilidad y ventajas de uso
    2. Parte 2 — Desempaquetado de valores
    3. Parte 3 — Conversión entre listas y tuplas
    4. Parte 4 — Ejemplos prácticos, buenas prácticas y ejercicios

    💡 Cada parte incluye ejemplos funcionales, tablas comparativas, y código
    resaltado con Prism.js para una mejor comprensión visual.

    📘 Parte 1 — Inmutabilidad y ventajas de uso

    En Python, las tuplas (tuple) son estructuras de datos muy parecidas a las listas,
    pero con una diferencia clave: son inmutables.
    Esto significa que, una vez creada una tupla, sus elementos no pueden modificarse.

    Por su naturaleza, las tuplas se usan cuando queremos proteger los datos o
    asegurar que una colección no cambie durante la ejecución del programa.


    🔹 Creación de tuplas

    Las tuplas se definen usando paréntesis () o simplemente separando valores por comas.

    
    # Tuplas con paréntesis
    numeros = (1, 2, 3, 4)
    
    # Tupla sin paréntesis (Python lo infiere)
    colores = "rojo", "verde", "azul"
    
    # Tupla con un solo elemento (nota la coma final)
    unidad = (5,)
    
    # Tupla vacía
    vacia = ()
      

    💡 Si olvidas la coma en una tupla de un solo elemento, Python la interpretará como un valor común.

    
    x = (5)
    print(type(x))  # ➜ <class 'int'>
    x = (5,)
    print(type(x))  # ➜ <class 'tuple'>
      

    🔒 ¿Qué significa “inmutabilidad”?

    Inmutabilidad significa que no se pueden alterar los elementos de una tupla después de su creación.

    
    animales = ("gato", "perro", "loro")
    animales[0] = "tigre"  # ❌ Error
      

    Este intento lanzará una excepción:

    
    TypeError: 'tuple' object does not support item assignment
      

    Por lo tanto, las tuplas son seguras contra modificaciones accidentales y ofrecen
    ventajas en rendimiento y uso en estructuras más avanzadas (como claves de diccionarios o conjuntos).


    🧩 Diferencias clave entre lista y tupla

    CaracterísticaLista (list)Tupla (tuple)
    MutabilidadMutable (puede modificarse)Inmutable (no puede cambiarse)
    Sintaxis[ ] (corchetes)( ) (paréntesis)
    VelocidadMás lentaMás rápida (por su inmutabilidad)
    Uso comúnListas dinámicas, pilas, colas, arreglosDatos fijos, coordenadas, configuraciones
    Ejemplo[1, 2, 3](1, 2, 3)

    🚀 Ventajas de las tuplas

    1. Mayor rendimiento: al ser inmutables, Python optimiza su almacenamiento en memoria.
    2. Seguridad de datos: nadie podrá modificar sus valores por error.
    3. Usables como claves en diccionarios: a diferencia de las listas.
    4. Menor consumo de recursos: ideales para grandes colecciones estáticas.
    5. Compatibilidad con estructuras avanzadas: como conjuntos (set) o
      estructuras hash.

    📏 Ejemplo práctico 1 — Coordenadas inmutables

    Un ejemplo clásico de uso de tuplas es el manejo de coordenadas que no deberían cambiar.

    
    # Coordenadas (x, y)
    punto = (10, 20)
    
    print("X:", punto[0])
    print("Y:", punto[1])
    
    # punto[0] = 50  # ❌ No permitido
      

    💡 Usar tuplas garantiza que las coordenadas se mantengan estables durante todo el programa.


    📊 Ejemplo práctico 2 — Registro de configuración

    Las tuplas son ideales para guardar configuraciones constantes:

    
    CONFIG_SERVIDOR = ("localhost", 8080, "HTTPS")
    
    for dato in CONFIG_SERVIDOR:
        print(dato)
      

    📘 En este caso, si alguien intenta modificar la configuración, Python lo impedirá.


    🧮 Ejemplo práctico 3 — Tuplas dentro de listas

    Puedes usar tuplas para almacenar elementos estructurados dentro de listas dinámicas.

    
    alumnos = [
        ("Ana", 9.2),
        ("Luis", 8.5),
        ("Sofía", 9.7)
    ]
    
    for nombre, nota in alumnos:
        print(f"{nombre}: {nota}")
      

    💡 Así, la lista puede modificarse (añadir o eliminar alumnos), pero cada registro individual
    permanece inmutable.


    📈 Ejemplo práctico 4 — Uso en diccionarios

    Las tuplas pueden usarse como claves en diccionarios, algo que no es posible con listas.

    
    # Claves compuestas con tuplas
    temperaturas = {
        ("Madrid", "Enero"): 6,
        ("Madrid", "Julio"): 31,
        ("Sevilla", "Enero"): 10
    }
    
    print(temperaturas[("Madrid", "Julio")])  # ➜ 31
      

    ✅ Las tuplas son hashables (pueden convertirse en hash) porque no cambian, lo que las hace válidas como claves.


    🧠 Cuándo usar una tupla en lugar de una lista

    • Cuando los datos no deben modificarse.
    • Cuando se requiere mejor rendimiento o seguridad.
    • Cuando se van a usar como clave en un diccionario.
    • Cuando trabajas con valores fijos como coordenadas, fechas o configuraciones.

    🧪 Mini-ejercicios

    1. Crea una tupla llamada meses con los nombres de los 12 meses. Muestra su longitud con len().
    2. Intenta modificar un elemento de esa tupla y observa el error que lanza Python.
    3. Crea una lista de tuplas con los nombres y edades de tres personas. Recorre la lista e imprime un saludo para cada una.
    4. Usa una tupla como clave en un diccionario para almacenar temperaturas de distintas ciudades y meses.

    🏁 Conclusión

    Las tuplas representan una forma eficiente, rápida y segura de almacenar datos fijos en Python.
    Su inmutabilidad las convierte en estructuras fundamentales para garantizar integridad y rendimiento.
    En la siguiente parte aprenderás a desempaquetar valores de una tupla de manera elegante y legible.

    🧩 Parte 2 — Desempaquetado de valores

    Una de las características más potentes y elegantes de las tuplas en Python es el
    desempaquetado de valores.
    Esto significa que puedes asignar varios valores de una tupla (o lista) a varias variables en una sola línea.


    🎯 ¿Qué es el desempaquetado?

    El desempaquetado consiste en asignar los elementos de una tupla directamente a variables
    individuales, sin necesidad de acceder por índice.

    
    # Tupla con tres valores
    punto = (10, 20, 30)
    
    # Desempaquetado
    x, y, z = punto
    
    print("X =", x)
    print("Y =", y)
    print("Z =", z)
      

    💡 Python “desempaqueta” cada elemento de la tupla en la variable correspondiente, siguiendo su posición.


    📦 Ejemplo práctico — Coordenadas geográficas

    
    ubicacion = ("Madrid", 40.4168, -3.7038)
    
    ciudad, latitud, longitud = ubicacion
    
    print(f"Ciudad: {ciudad}")
    print(f"Latitud: {latitud}")
    print(f"Longitud: {longitud}")
      

    ✅ El código se vuelve más legible y semántico; las variables toman nombres descriptivos en lugar de índices numéricos.


    🔢 Desempaquetado parcial

    Si solo te interesa parte de los valores, puedes ignorar algunos usando el guion bajo _ como variable temporal.

    
    persona = ("Javier", 34, "Madrid")
    
    nombre, _, ciudad = persona
    
    print(nombre, "vive en", ciudad)
      

    💡 El guion bajo indica que no necesitas ese valor (convención común en Python).


    🧮 Desempaquetado en bucles

    El desempaquetado también se usa dentro de bucles for para recorrer listas de tuplas.

    
    alumnos = [
        ("Ana", 9.2),
        ("Luis", 8.5),
        ("Sofía", 9.7)
    ]
    
    for nombre, nota in alumnos:
        print(f"{nombre} obtuvo {nota}")
      

    ✅ El código es más limpio y evita accesos por índice (alumno[0], alumno[1]).


    ⚙️ Intercambio de valores con desempaquetado

    Gracias al desempaquetado, puedes intercambiar el contenido de dos variables sin usar una variable auxiliar.

    
    a = 5
    b = 10
    
    a, b = b, a
    
    print("a =", a)  # ➜ 10
    print("b =", b)  # ➜ 5
      

    💡 Este truco idiomático es ampliamente usado en Python por su legibilidad y simplicidad.


    🧠 Desempaquetado extendido con asterisco (*)

    Si no conoces el número exacto de elementos, puedes usar el operador asterisco *
    para capturar varios valores en una lista.

    
    datos = (1, 2, 3, 4, 5)
    
    a, b, *resto = datos
    print(a, b, resto)
    # ➜ 1 2 [3, 4, 5]
    
    # También al final:
    *a, b = datos
    print(a, b)
    # ➜ [1, 2, 3, 4] 5
      

    Regla: el asterisco solo puede usarse una vez en la asignación.


    📊 Ejemplo — Calificaciones dinámicas

    
    registro = ("Ana", 9, 8, 10, 9.5)
    
    nombre, *notas = registro
    
    print("Estudiante:", nombre)
    print("Notas:", notas)
    print("Promedio:", sum(notas) / len(notas))
      

    💡 El operador * te permite capturar un número variable de elementos sin saber cuántos habrá.


    🧱 Desempaquetado en funciones

    Las tuplas son útiles para retornar varios valores desde una función.

    
    def dividir(dividendo, divisor):
        cociente = dividendo // divisor
        resto = dividendo % divisor
        return cociente, resto  # devuelve una tupla
    
    resultado = dividir(10, 3)
    print(resultado)  # ➜ (3, 1)
    
    # Desempaquetado directo
    cociente, resto = dividir(10, 3)
    print(f"Cociente: {cociente}, Resto: {resto}")
      

    ✅ Así puedes recibir varios valores de retorno de manera ordenada y clara.


    📦 Desempaquetado anidado

    Python también permite desempaquetar estructuras anidadas (tuplas dentro de tuplas).

    
    punto3D = ("Origen", (0, 0, 0))
    
    nombre, (x, y, z) = punto3D
    
    print(nombre)
    print(f"Coordenadas: X={x}, Y={y}, Z={z}")
      

    💡 Este tipo de desempaquetado es muy útil cuando trabajas con datos estructurados o JSON anidados.


    📋 Tabla resumen de desempaquetado

    TipoEjemploResultado
    Básicox, y = (1, 2)x=1, y=2
    Parcialx, _, z = (1, 2, 3)x=1, z=3
    Extendidox, *resto = (1,2,3,4)x=1, resto=[2,3,4]
    Anidado(a, (b, c)) = ("A", (1, 2))a="A", b=1, c=2

    🧪 Mini-ejercicios

    1. Crea una tupla info con nombre, edad y ciudad. Desempaquétala en tres variables y muéstralas en una sola línea.
    2. Usa * para capturar una lista de calificaciones en una tupla ("Juan", 8, 9, 10, 7).
    3. Desempaqueta una lista de tuplas [("A",1),("B",2),("C",3)] en un bucle.
    4. Devuelve una tupla desde una función que contenga (suma, media) de una lista numérica, y desempaquétala al recibirla.
    5. Haz un desempaquetado anidado de la tupla ("usuario", ("Javi", "Madrid")).

    🏁 Conclusión

    El desempaquetado es una de las características más expresivas y limpias de Python.
    Permite escribir código más natural, legible y eficiente.
    En la siguiente parte aprenderás cómo convertir entre listas y tuplas fácilmente,
    combinando lo mejor de ambos mundos.

    🔄 Parte 3 — Conversión entre list y tuple

    En Python es habitual alternar entre listas (mutables) y tuplas (inmutables) según la fase del programa:
    edito datos ➜ lista; congelo datos ➜ tupla.
    Aquí verás cómo convertir en ambos sentidos, qué implicaciones tiene y patrones seguros para el día a día.


    ✅ Convertir lista → tupla

    Usa tuple(iterable) para crear una tupla a partir de cualquier iterable (lista, cadena, rango, generador, etc.).

    
    frutas_lista = ["manzana", "pera", "uva"]
    frutas_tupla = tuple(frutas_lista)
    print(frutas_tupla)        # ('manzana', 'pera', 'uva')
    print(type(frutas_tupla))  # <class 'tuple'>
      
    • Congelación lógica: tras convertir a tupla, el contenedor ya no puede modificarse.
    • Copia superficial: si los elementos son mutables (p. ej., listas), la tupla solo “congela” la referencia, no el contenido interno.
    
    # Cuidado con anidados mutables
    datos = [[1,2], [3,4]]
    t = tuple(datos)     # congela las referencias, NO el contenido
    datos[0].append(99)
    print(t)             # ([1, 2, 99], [3, 4])  ← cambió por dentro
      
    Tip: si necesitas inmutabilidad profunda, crea copias inmutables de los elementos internos (p. ej., tuple(map(tuple, lista_de_listas))).

    ✅ Convertir tupla → lista

    Usa list(iterable) para obtener una copia mutable que puedas editar.

    
    puntos = (10, 20, 30)
    puntos_lista = list(puntos)
    puntos_lista[0] = 99
    print(puntos_lista)  # [99, 20, 30]
      

    Patrón común: “descongelo, edito, vuelvo a congelar”.

    
    coordenadas = (100, 200, 300)
    
    # Descongelar
    tmp = list(coordenadas)
    # Editar
    tmp.append(400)
    tmp[1] = 250
    # Volver a congelar
    coordenadas = tuple(tmp)
    
    print(coordenadas)  # (100, 250, 300, 400)
      

    📦 Conversiones frecuentes con otros iterables

    OrigenDestinoEjemploResultado
    Cadena (str)Listalist("Hola")['H','o','l','a']
    Cadena (str)Tuplatuple("OK")('O','K')
    rangeListalist(range(3))[0,1,2]
    GeneradorTuplatuple(x*x for x in range(4))(0,1,4,9)
    DiccionarioLista de claveslist({'a':1,'b':2})['a','b']
    DiccionarioTupla de parestuple({'a':1,'b':2}.items())(('a',1),('b',2))

    ⚙️ Conversión al vuelo con comprensiones y map

    No existe “tupla por comprensión” como tal: usamos un generador y luego tuple(...).

    
    # Lista por comprensión
    L = [x*x for x in range(5)]     # [0, 1, 4, 9, 16]
    
    # Tupla desde generador
    T = tuple(x*x for x in range(5))  # (0, 1, 4, 9, 16)
    
    # Conversión con map
    T2 = tuple(map(str, [1, 2, 3]))   # ('1', '2', '3')
      

    🧠 Patrones de uso típicos

    1) Lista para construir, tupla para entregar (API/return)

    
    def top3(scores):
        # construir, ordenar y congelar
        tmp = sorted(scores, reverse=True)[:3]
        return tuple(tmp)
    
    print(top3([8, 10, 6, 9, 9.5]))  # (10, 9.5, 9)
      

    2) Claves de diccionario compuestas (tupla)

    
    # (ciudad, mes) como clave inmutable
    temperaturas = {}
    clave = tuple(["Madrid", "Enero"])
    temperaturas[clave] = 6
      

    3) Sellar configuraciones

    
    # Partes mutables durante setup
    hosts = ["app01", "app02", "app03"]
    # Publicar como inmutable
    HOSTS_PUBLICOS = tuple(hosts)
      

    🧪 Conversión y mutabilidad: casos a tener en cuenta

    Escenario A: “congelar” instantáneas de listas que cambian.

    
    lista = [1, 2, 3]
    snap = tuple(lista)  # snapshot
    lista.append(4)
    print(snap)          # (1, 2, 3)  ← no cambia
      

    Escenario B: elementos mutables dentro de una tupla.

    
    t = ([1,2], [3,4])   # tupla con listas mutables
    t[0].append(99)
    print(t)  # ([1, 2, 99], [3, 4]) ← “inmutabilidad superficial”
      
    Regla mental: la tupla no cambia de forma, pero lo que contiene podría cambiar si es mutable.

    📈 Rendimiento y memoria (visión práctica)

    • Tuplas suelen ocupar menos memoria y pueden ser ligeramente más rápidas en acceso.
    • Convertir con tuple() / list() crea nuevos contenedores (O(n)). Evita reconversiones innecesarias en bucles críticos.
    • Si necesitas una sola lectura secuencial, considera generadores para ahorrar memoria:
    
    # Evita materializar si no es necesario:
    # tuple(range(10_000_000))  # ⚠️ gigante en memoria
    suma = sum(x for x in range(10_000_000))  # generador: memoria eficiente
      

    🧩 Conversión en pipelines (limpieza / normalización)

    
    raw = ["  Ana ", "Luis", "  Sofía  "]
    
    # Normalizo con lista (editable)…
    tmp = [nombre.strip() for nombre in raw]
    tmp = [n.capitalize() for n in tmp]
    
    # …y sello en tupla para publicar
    alumnos = tuple(tmp)
    print(alumnos)  # ('Ana', 'Luis', 'Sofía')
      

    📋 Tabla resumen

    OperaciónUsoComentarios
    tuple(lista)Lista → TuplaCongela; copia superficial
    list(tupla)Tupla → ListaPermite editar
    tuple(iterable)Cualquier iterable → TuplaIncluye generadores; evalúa todo
    list(iterable)Cualquier iterable → ListaMaterializa en memoria
    tuple(map(f, X))Transformar y congelarPatrón pipeline
    tuple(x for x in X)Generador → Tupla“Tupla por comprensión” idiomática

    🧪 Mini-ejercicios

    1. Dada ["A","b"," c "], genera ("A","B","C") normalizando espacios y mayúsculas.
    2. Convierte (1,2,3) en lista, inserta 99 al inicio y vuelve a tupla.
    3. Crea una tupla inmutable de pares (nombre, nota) a partir de listas separadas usando zip() y tuple().
    4. “Congela profundamente” una lista de listas en tupla de tuplas (pista: map(tuple, ...)).
    5. Convierte una tupla de cadenas en una lista de enteros seguros (usa int y manejo de errores si hay valores no numéricos).

    🏁 Conclusión

    Dominar la conversión entre list y tuple te da control total sobre mutabilidad, rendimiento y diseño de APIs.
    Usa listas para construir y transformar; usa tuplas para publicar, pasar como clave o garantizar integridad.

    🧪 Parte 4 — Ejemplos prácticos, buenas prácticas y ejercicios

    Hora de operacionalizar las tuplas. En esta parte verás casos reales,
    patrones profesionales y anti-patrones frecuentes. Objetivo: escribir código
    más robusto, legible y performante aprovechando la inmutabilidad.


    ✅ Caso 1 — Catálogo (lista de tuplas inmutables)

    Modelo de datos minimalista y seguro para listar productos: (id, nombre, precio).

    
    catalogo = [
        (101, "Teclado", 29.9),
        (102, "Ratón", 19.9),
        (103, "Monitor", 149.0),
    ]
    
    # Iteración con desempaquetado
    for pid, nombre, precio in catalogo:
        print(f"#{pid} — {nombre}: {precio} €")
    
    # Búsqueda por id (con for...else)
    buscado = 102
    for pid, nombre, precio in catalogo:
        if pid == buscado:
            print("Encontrado:", (pid, nombre, precio))
            break
    else:
        print("No existe el producto", buscado)
      

    Por qué tuplas: el “registro” de producto no debe mutar accidentalmente dentro del flujo.


    ✅ Caso 2 — Claves compuestas en diccionarios

    Tuplas como clave para indexar por múltiples dimensiones: (ciudad, mes).

    
    temperaturas = {
        ("Madrid", "Enero"): 6,
        ("Madrid", "Julio"): 31,
        ("Sevilla", "Julio"): 36,
    }
    print(temperaturas[("Madrid", "Julio")])  # 31
      

    Ventaja: hashable + semántica clara.


    ✅ Caso 3 — Retorno múltiple limpio

    Devuelve varios valores como tupla. El consumidor decide desempaquetar o no.

    
    def stats(numeros):
        total = sum(numeros)
        n = len(numeros)
        media = total / n if n else 0
        minimo, maximo = (min(numeros), max(numeros)) if n else (None, None)
        return media, minimo, maximo  # tupla
    
    m, lo, hi = stats([10, 5, 8, 3])
    print(m, lo, hi)
      

    ✅ Caso 4 — Ordenación por múltiples campos

    El orden lexicográfico de tuplas simplifica el sorting.

    
    alumnos = [
        ("Ana", 2, 9.2),
        ("Luis", 1, 8.1),
        ("Sofía", 3, 9.2),
    ]
    
    # Ordena por (nota DESC, curso ASC, nombre ASC)
    alumnos_ordenados = sorted(
        alumnos,
        key=lambda t: (-t[2], t[1], t[0])
    )
    print(alumnos_ordenados)
      

    ✅ Caso 5 — Pipeline: construir mutable, publicar inmutable

    
    raw = ["  Ana", "luis  ", "SOFIA"]
    tmp = [s.strip().capitalize() for s in raw]  # editable
    ALUMNOS = tuple(tmp)                          # sellado
    print(ALUMNOS)  # ('Ana', 'Luis', 'Sofia')
      

    ✅ Caso 6 — CSV ligero a tuplas

    Convertir líneas de texto en tuplas inmutables para procesamiento downstream.

    
    lineas = [
        "id,nombre,precio",
        "101,Teclado,29.9",
        "102,Ratón,19.9",
    ]
    encabezado = tuple(lineas[0].split(","))  # ('id','nombre','precio')
    filas = [tuple(l.split(",")) for l in lineas[1:]]
    print(encabezado)
    print(filas)
      

    🧠 Buenas prácticas (playbook ejecutivo)

    PrácticaPor quéSnippet
    Usa tuplas para registros estáticosIntegridad + rendimiento("id", "nombre", precio)
    Desempaquetado para legibilidadNombres expresivos > índicesuser, rol = ("javi","admin")
    Claves compuestasIndexación multidimensionaldatos[(anio, mes)] = valor
    “Construir con lista, publicar tupla”Flujo natural de mutabilidadfinal = tuple(tmp)
    Ordenación por múltiples camposLexicográfico nativosorted(X, key=lambda t: (t[0], -t[1]))

    ⚠️ Anti-patrones comunes (y su fix)

    Anti-patrónProblemaSolución
    Olvidar la coma en tupla unitaria(5) es int, no tupla(5,)
    Modificar “tupla” con elementos mutables internosLa inmutabilidad es superficialNormaliza: tuple(map(tuple, lista))
    Abusar de índices mágicosBaja legibilidadDesempaqueta: nombre, nota = alumno
    Reconstruir tuplas en bucles críticosCoste O(n) repetidoConvierte una vez; evita reconversiones

    🧩 Trucos y patrones útiles

    Swap (intercambio sin variable temporal)

    
    a, b = 1, 9
    a, b = b, a
      

    Desempaquetado extendido

    
    primero, *centro, ultimo = (1, 2, 3, 4, 5)
    # primero=1, centro=[2,3,4], ultimo=5
      

    Comparación lexicográfica de tuplas

    
    print((1, 5) < (2, 0))   # True (compara por orden)
    print((1, 5) < (1, 7))   # True
      

    Validación de estructura rápida

    
    def es_registro_producto(t):
        return isinstance(t, tuple) and len(t) == 3 and isinstance(t[0], int)
      

    🧪 Miniproyecto 1 — Agenda de contactos

    Estructura: lista de tuplas (nombre, telefono, email).

    
    agenda = [
        ("Ana", "600-111-111", "ana@example.com"),
        ("Luis", "600-222-222", "luis@example.com"),
    ]
    
    def buscar(agenda, nombre):
        for n, tel, correo in agenda:
            if n.lower() == nombre.lower():
                return (n, tel, correo)  # tupla
        return None
    
    print(buscar(agenda, "ana"))
      

    🧪 Miniproyecto 2 — Ranking (orden múltiple)

    
    ranking = [
        ("Ana", 3, 95.5),   # (nombre, fallos, puntuación)
        ("Luis", 1, 90.0),
        ("Sofia", 1, 95.5),
    ]
    # Criterio: puntuación DESC, fallos ASC, nombre ASC
    ordenado = sorted(ranking, key=lambda t: (-t[2], t[1], t[0]))
    for nombre, fallos, score in ordenado:
        print(nombre, fallos, score)
      

    🧪 Miniproyecto 3 — Matriz inmutable (tupla de tuplas)

    
    # Construcción desde lista de listas (editable) a tupla de tuplas (sellada)
    matriz_lista = [
        [1, 2, 3],
        [4, 5, 6]
    ]
    M = tuple(map(tuple, matriz_lista))
    print(M)               # ((1,2,3),(4,5,6))
    print(M[0][1])         # 2
    # M[0][1] = 99        # ❌ TypeError
      

    📊 Cheatsheet rápido

    TareaSnippet
    Tupla unitaria(valor,)
    Desempaquetara, b = tupla
    Desempaquetado extendidoa, *resto = tupla
    Lista → Tuplatuple(lista)
    Tupla → Listalist(tupla)
    Congelar 2Dtuple(map(tuple, lista_2d))
    Orden múltiplesorted(X, key=lambda t: (...))
    Clave compuestadic[(k1, k2)] = valor

    📝 Ejercicios propuestos

    1. Inventario inmutable: crea una lista de tuplas (sku, nombre, stock).
      Escribe una función que devuelva el sku con menor stock (usa ordenación por tupla).
    2. Notas por alumno: recibe ("Nombre", *notas), calcula media y devuelve
      (nombre, media). Procesa una lista completa y ordénala por media desc.
    3. Claves compuestas: crea un dict para registrar ventas por (año, mes).
      Implementa una función que sume el total anual.
    4. Normalización: a partir de [" aNA ", "lUiS", " soFIA "] devuelve una tupla
      ("Ana","Luis","Sofia") (pipeline + sellado).
    5. Transpuesta segura: convierte una lista de listas en tupla de tuplas y genera su transpuesta
      (ambas inmutables).

    🏁 Conclusión

    Las tuplas son el estándar de oro para datos inmutables en Python: compactas, rápidas,
    legibles y con potentes usos en ordenación y claves compuestas. Ya tienes el toolkit para aplicarlas con criterio en
    producción.

    Nuestra puntuación
    ¡Haz clic para puntuar esta entrada!
    (Votos: 0 Promedio: 0)
    Scroll al inicio