Tuplas y desempaquetado
Una lista que no se puede cambiar cuando es justo lo que quieres, desempaquetar para usar nombres en vez de índices, intercambiar dos variables en una sola línea, y la trampa de (5) frente a (5,).
¿Cómo quieres aprender?
El problema que vamos a resolver
Hay que registrar el tiempo de tres días —para cada día, el nombre, la temperatura y la humedad—.
Una lista hace el trabajo: ["monday", 31.5, 78]. Funciona, y aun así hay dos cosas que molestan.
Primero, esa lista se puede cambiar. Si algo hace append al registro del lunes por error, Python no dirá ni palabra —aunque un registro nunca debería tener cuatro cosas—. Poner algo que no debe cambiar dentro de un contenedor que sí se puede cambiar es un riesgo silencioso.
Segundo, sacar los tres valores de nuevo significa escribir record[0], record[1], record[2] —por número, no por nombre—. Seis meses después, nadie que lea record[1] sabrá si eso es la temperatura o la humedad.
Una tupla resuelve las dos: es una lista que no se puede cambiar —y trae una capacidad llamada desempaquetado, que te deja usar nombres en vez de índices—.
Al terminar este capítulo podrás
- Crear una tupla y decir cuándo encaja una tupla y no una lista
- Poner varios valores en varios nombres de una sola vez con el desempaquetado
- Intercambiar dos variables en una sola línea
- Distinguir
(5)de(5,) - Explicar por qué
appendsobre una tupla lanza unAttributeError
Requisitos previos: Ordenar listas, y los métodos que vienen con ellas.
Una tupla — una lista que no se puede cambiar
Paréntesis redondos en lugar de corchetes:
point = (3, 7)
print(point)
print(point[0])
print(len(point))(3, 7)
3
2Leer, indexar, len, hacer slices, in, recorrer con for —todo lo que hacías con una lista funciona—. Hay una sola diferencia, y lo es todo:
point = (3, 7)
point[0] = 5TypeError: 'tuple' object does not support item assignment¿Te suena ese mensaje? Es literalmente el mismo que dio el capítulo seis cuando se cambió un carácter dentro de un texto, con 'str' en lugar de 'tuple'. Todas las cosas inmutables de Python se quejan en el mismo idioma.
Los métodos que cambian cosas tampoco están:
point = (3, 7)
point.append(9)AttributeError: 'tuple' object has no attribute 'append'Un AttributeError significa "este objeto no tiene nada con ese nombre". Una tupla no se puede cambiar, así que una tupla no tiene ningún método llamado append. Python se detiene al buscar point.append, sin llegar siquiera a intentar añadir 9. Compáralo con el ejemplo anterior: point[0] = 5 pedía una operación que una tupla no permite, así que eso fue un TypeError; aquí el método en sí no existe, así que es un AttributeError.
Por qué esto es una ventaja, no una limitación
Al principio una tupla parece una lista a la que le quitaron cosas. Dalo la vuelta: si algo no debe cambiar, ponerlo donde no puede cambiar evita el error antes de que ocurra.
No tiene sentido añadir un tercer número a la coordenada (3, 7). Una fecha (2026, 9, 16) no tiene cuarta parte. Guardadas en tuplas, esos accidentes llegan como errores al instante en vez de como bugs más tarde.
Como regla: una cantidad fija de cosas, cada una con un significado distinto —tupla—. Una cantidad desconocida de cosas, todas del mismo tipo —lista—.
Así que tres días de tiempo son tuplas dentro de una lista: la cantidad de días no se conoce (una lista), pero cada registro contiene exactamente tres cosas (una tupla).
Desempaquetado — donde está el verdadero beneficio
point = (3, 7)
x, y = point
print(x)
print(y)3
7Dos nombres y dos valores en una sola línea. Y ahora es y y no point[1] —un nombre que se explica solo cuando lo lees—.
Tiene que haber tantos nombres a la izquierda como valores a la derecha:
point = (3, 7)
x, y, z = pointValueError: not enough values to unpack (expected 3, got 2)Ese mensaje es inusualmente útil —te dice cuántos se esperaban y cuántos llegaron—.
El desempaquetado no se limita a las tuplas; también funciona con listas. Es más útil con las tuplas porque ahí la cantidad de valores se conoce de antemano.
Intercambio en una sola línea
Otros lenguajes necesitan una tercera variable temporal para intercambiar dos valores. Python no:
a = 1
b = 2
a, b = b, a
print(a, b)2 1Vale la pena entender cómo funciona la línea: Python evalúa primero todo el lado derecho, construyendo la tupla (2, 1), y después la desempaqueta hacia la izquierda. Así que aunque a cambia, el valor anterior de b ya quedó guardado en esa tupla, y no se pierde nada.
Los paréntesis en realidad no hacen falta
point = 3, 7
print(point)
print(type(point))(3, 7)
<class 'tuple'>Lo que hace una tupla es la coma, no los paréntesis. Los paréntesis están ahí por legibilidad. Cuando lo sabes, a, b = b, a deja de parecer magia —b, a a la derecha es simplemente una tupla—.
Y de ahí sale una trampa:
one = (5)
really = (5,)
print(type(one))
print(type(really))
print(len(really))<class 'int'>
<class 'tuple'>
1(5) no es una tupla —es un número entre paréntesis, igual que (2 + 3). Construir una tupla de un valor exige la coma: (5,). Parece un error de tecleo, y esa coma es toda la diferencia.
Tuplas en un bucle
people = [("rafi", 22), ("ahmed", 35)]
for name, age in people:
print(f"{name} is {age}")rafi is 22
ahmed is 35for name, age in people desempaqueta cada tupla directamente en dos nombres. Sin person[0] ni person[1] —y el código dice lo que significa cuando lo lees—.
Ya lo has usado sin saberlo:
stock = ["pen", "bag"]
for pair in enumerate(stock):
print(pair)(0, 'pen')
(1, 'bag')enumerate devuelve tuplas. Escribir for position, item in enumerate(...) en el capítulo doce era desempaquetarlas —solo que no teníamos nombre para ello—.
Convertir de una a otra
as_list = [3, 7]
as_tuple = (3, 7)
as_list.append(9)
print(as_list)
print(as_tuple)
print(list(as_tuple))
print(tuple(as_list))[3, 7, 9]
(3, 7)
[3, 7]
(3, 7, 9)list() y tuple() construyen una a partir de la otra —una cosa nueva cada vez, dejando la original intacta—. Así es como se "cambia" una tupla: haz una lista, cámbiala, vuelve a hacer una tupla.
Un ejemplo completo
weather.py:
# A tuple is the right shape for a record that must not change
readings = [
("monday", 31.5, 78),
("tuesday", 33.0, 71),
("wednesday", 29.5, 85),
]
print("Day Temp Humidity")
for day, temp, humidity in readings:
print(f"{day:<10} {temp:>5} {humidity:>5}")
hottest = readings[0]
for reading in readings:
if reading[1] > hottest[1]:
hottest = reading
day, temp, humidity = hottest
print()
print(f"Hottest was {day} at {temp}")
temps = []
for _, temp, _ in readings:
temps.append(temp)
print("Temps :", temps)
print("Average :", round(sum(temps) / len(temps), 2))Day Temp Humidity
monday 31.5 78
tuesday 33.0 71
wednesday 29.5 85
Hottest was tuesday at 33.0
Temps : [31.5, 33.0, 29.5]
Average : 31.33Cuatro cosas que merece la pena notar.
Una lista por fuera, tuplas por dentro. La cantidad de días puede crecer, así que lo de fuera es una lista. Cada registro contiene exactamente tres cosas, así que lo de dentro son tuplas. Esa es la forma más común en la que llegan los datos reales.
f"{day:<10}" y f"{temp:>5}" mantienen las columnas alineadas. < alinea a la izquierda, > a la derecha, y el número dice cuánta anchura ocupar. Igual que el :.2f del capítulo seis, todo lo que va después de los dos puntos es formato.
Encontrar el día más caluroso necesitó reading[1], porque durante la comparación se tiene la tupla completa en la mano y no una ya desempaquetada. Se desempaqueta en cuanto se encuentra —por eso la línea siguiente no lleva ningún índice—.
for _, temp, _ in readings —el guion bajo es una convención que significa "este no me hace falta". Para Python es un nombre cualquiera; para quien lee, dice qué partes se están descartando a propósito—.
Cuando falla
TypeError: 'tuple' object does not support item assignment Un intento de cambiar un valor dentro de una tupla. Las tuplas no se pueden cambiar —usa una lista desde el principio, o convierte con list(...), cámbiala y vuelve a convertirla—.
AttributeError: 'tuple' object has no attribute 'append' La misma causa con otro disfraz. Ningún método que cambie cosas —append, remove, sort— existe en una tupla. sorted(my_tuple) sí funciona, porque devuelve una lista nueva y deja la tupla intacta.
ValueError: not enough values to unpack (expected 3, got 2) Hay más nombres a la izquierda que valores a la derecha. print(len(record)) muestra cuántos hay en realidad dentro.
ValueError: too many values to unpack (expected 2) Lo contrario —más valores que nombres—.
Hice una tupla de un valor y no es una tupla Falta la coma. (5) es un número; (5,) es una tupla.
Una lista dentro de mi tupla cambió Una tupla protege su propia estructura —qué cosas hay dentro no puede cambiar. Pero si una de esas cosas es a su vez modificable, como una lista, el interior de esa lista todavía puede cambiar. En ([1, 2], 3) puedes hacer append a la primera lista.
Paso 4 de 6 — Predice
Comprueba lo que has entendido
¿Qué se imprime después del desempaquetado?
point = (3, 7)
x, y = point
print(y, x)- A3 7
- B(3, 7)
- CUn `ValueError`
- D7 3
Se intenta hacer append a una tupla. ¿Qué error sale, y por qué ese?
point = (3, 7)
point.append(9)- AUn `ValueError`
- BNo pasa nada; la tupla queda igual
- CUn `AttributeError` — una tupla no puede cambiar, así que los métodos que cambian simplemente no existen en ella
- DUn `TypeError` — `append` no está permitido en una tupla
Las dos líneas difieren en una coma. ¿Qué informa type()?
one = (5)
really = (5,)
print(type(one))
print(type(really))- A<class 'int'> <class 'int'>
- B<class 'tuple'> <class 'tuple'>
- C<class 'int'> <class 'tuple'>
- D<class 'tuple'> <class 'int'>
Para responder necesitas una cuenta
Inicia sesión para comprobar tus respuestas
Las preguntas están arriba, y resolverlas mentalmente es lo que de verdad importa. Inicia sesión para ver las respuestas, las explicaciones y las pistas de tres niveles.
Tu turno
Escribe un archivo llamado contacts.py con una lista de al menos cinco personas, cada una una tupla de un nombre, una edad y una materia favorita.
Luego:
- Imprime a todos en columnas alineadas, usando
for name, age, subject in contacts: - Encuentra a la persona de mayor edad, desempaquétala e imprime una frase sobre ella
- Construye una lista solo con los nombres e imprímelos en una sola línea con
join - Imprime la edad media
- Intercambia dos variables en una sola línea y demuestra que funcionó
Luego rompélo tres veces a propósito y lee cada mensaje:
- Intenta cambiar la edad dentro de una de las tuplas
- Intenta hacer
appenda una tupla - Intenta desempaquetar una tupla de tres valores en dos nombres
Volverán tres errores distintos —TypeError, AttributeError, ValueError—. Saber explicarte a ti mismo cuál es cuál y por qué significa que las tuplas ya son tuyas.
Paso 6 de 6
Reto — el quiz del capítulo
Diez preguntas de fácil a difícil. Las últimas son difíciles a propósito.
Inicia sesión para hacer el quiz