📘 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.
- Parte 1 — Inmutabilidad y ventajas de uso
- Parte 2 — Desempaquetado de valores
- Parte 3 — Conversión entre listas y tuplas
- 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ística | Lista (list ) | Tupla (tuple ) |
---|---|---|
Mutabilidad | Mutable (puede modificarse) | Inmutable (no puede cambiarse) |
Sintaxis | [ ] (corchetes) | ( ) (paréntesis) |
Velocidad | Más lenta | Más rápida (por su inmutabilidad) |
Uso común | Listas dinámicas, pilas, colas, arreglos | Datos fijos, coordenadas, configuraciones |
Ejemplo | [1, 2, 3] | (1, 2, 3) |
🚀 Ventajas de las tuplas
- Mayor rendimiento: al ser inmutables, Python optimiza su almacenamiento en memoria.
- Seguridad de datos: nadie podrá modificar sus valores por error.
- Usables como claves en diccionarios: a diferencia de las listas.
- Menor consumo de recursos: ideales para grandes colecciones estáticas.
- 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
- Crea una tupla llamada
meses
con los nombres de los 12 meses. Muestra su longitud conlen()
. - Intenta modificar un elemento de esa tupla y observa el error que lanza Python.
- Crea una lista de tuplas con los nombres y edades de tres personas. Recorre la lista e imprime un saludo para cada una.
- 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
Tipo | Ejemplo | Resultado |
---|---|---|
Básico | x, y = (1, 2) | x=1, y=2 |
Parcial | x, _, z = (1, 2, 3) | x=1, z=3 |
Extendido | x, *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
- Crea una tupla
info
con nombre, edad y ciudad. Desempaquétala en tres variables y muéstralas en una sola línea. - Usa
*
para capturar una lista de calificaciones en una tupla("Juan", 8, 9, 10, 7)
. - Desempaqueta una lista de tuplas
[("A",1),("B",2),("C",3)]
en un bucle. - Devuelve una tupla desde una función que contenga (suma, media) de una lista numérica, y desempaquétala al recibirla.
- 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
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
Origen | Destino | Ejemplo | Resultado |
---|---|---|---|
Cadena (str ) | Lista | list("Hola") | ['H','o','l','a'] |
Cadena (str ) | Tupla | tuple("OK") | ('O','K') |
range | Lista | list(range(3)) | [0,1,2] |
Generador | Tupla | tuple(x*x for x in range(4)) | (0,1,4,9) |
Diccionario | Lista de claves | list({'a':1,'b':2}) | ['a','b'] |
Diccionario | Tupla de pares | tuple({'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”
📈 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ón | Uso | Comentarios |
---|---|---|
tuple(lista) | Lista → Tupla | Congela; copia superficial |
list(tupla) | Tupla → Lista | Permite editar |
tuple(iterable) | Cualquier iterable → Tupla | Incluye generadores; evalúa todo |
list(iterable) | Cualquier iterable → Lista | Materializa en memoria |
tuple(map(f, X)) | Transformar y congelar | Patrón pipeline |
tuple(x for x in X) | Generador → Tupla | “Tupla por comprensión” idiomática |
🧪 Mini-ejercicios
- Dada
["A","b"," c "]
, genera("A","B","C")
normalizando espacios y mayúsculas. - Convierte
(1,2,3)
en lista, inserta99
al inicio y vuelve a tupla. - Crea una tupla inmutable de pares
(nombre, nota)
a partir de listas separadas usandozip()
ytuple()
. - “Congela profundamente” una lista de listas en tupla de tuplas (pista:
map(tuple, ...)
). - 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áctica | Por qué | Snippet |
---|---|---|
Usa tuplas para registros estáticos | Integridad + rendimiento | ("id", "nombre", precio) |
Desempaquetado para legibilidad | Nombres expresivos > índices | user, rol = ("javi","admin") |
Claves compuestas | Indexación multidimensional | datos[(anio, mes)] = valor |
“Construir con lista, publicar tupla” | Flujo natural de mutabilidad | final = tuple(tmp) |
Ordenación por múltiples campos | Lexicográfico nativo | sorted(X, key=lambda t: (t[0], -t[1])) |
⚠️ Anti-patrones comunes (y su fix)
Anti-patrón | Problema | Solución |
---|---|---|
Olvidar la coma en tupla unitaria | (5) es int, no tupla | (5,) |
Modificar “tupla” con elementos mutables internos | La inmutabilidad es superficial | Normaliza: tuple(map(tuple, lista)) |
Abusar de índices mágicos | Baja legibilidad | Desempaqueta: nombre, nota = alumno |
Reconstruir tuplas en bucles críticos | Coste O(n) repetido | Convierte 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
Tarea | Snippet |
---|---|
Tupla unitaria | (valor,) |
Desempaquetar | a, b = tupla |
Desempaquetado extendido | a, *resto = tupla |
Lista → Tupla | tuple(lista) |
Tupla → Lista | list(tupla) |
Congelar 2D | tuple(map(tuple, lista_2d)) |
Orden múltiple | sorted(X, key=lambda t: (...)) |
Clave compuesta | dic[(k1, k2)] = valor |
📝 Ejercicios propuestos
- 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). - Notas por alumno: recibe
("Nombre", *notas)
, calcula media y devuelve(nombre, media)
. Procesa una lista completa y ordénala por media desc. - Claves compuestas: crea un
dict
para registrar ventas por(año, mes)
.
Implementa una función que sume el total anual. - Normalización: a partir de
[" aNA ", "lUiS", " soFIA "]
devuelve una tupla("Ana","Luis","Sofia")
(pipeline + sellado). - 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.