Listas, tuplas, diccionarios y conjuntos resuelven casi todo en Python. Esta lección va de cuándo usar cada uno, de la diferencia entre d["x"] y d.get("x") —que causa la mitad de los errores— y de una copia que no copia.
Cuatro estructuras, y cuándo cada una
| Ordenada | Mutable | Repetidos | Se escribe | |
|---|---|---|---|---|
list |
sí | sí | sí | [1, 2, 3] |
tuple |
sí | no | sí | (1, 2, 3) |
dict |
sí (por inserción) | sí | claves no | {"a": 1} |
set |
no | sí | no | {1, 2, 3} |
Listas
compra = ["pan", "uva", "pan"]
compra.append("kiwi")
compra.insert(0, "sal")
compra[1:3] # rebanada
compra[::-1] # al revés
compra.remove("pan")
compra.pop()
salida['sal', 'pan', 'uva', 'pan', 'kiwi'] len=5
compra[0]=sal compra[-1]=kiwi compra[1:3]=['pan', 'uva']
compra[::-1] = ['kiwi', 'pan', 'uva', 'pan', 'sal']
tras remove('pan'): ['sal', 'uva', 'pan', 'kiwi'] (solo quita la primera)
pop() devuelve 'kiwi' y deja ['sal', 'uva', 'pan']
Dos cosas que conviene interiorizar pronto. Los índices negativos cuentan desde el final: [-1] es el último, sin necesidad de calcular la longitud. Y las rebanadas [inicio:fin] incluyen el inicio y excluyen el fin, igual que range; por eso [1:3] da dos elementos.
remove quita solo la primera aparición, y si no está lanza ValueError.
Tuplas
punto = (3, 4) x, y = punto # desempaquetado punto[0] = 9
salidadesempaquetado: x=3 y=4 TypeError: 'tuple' object does not support item assignment
Una tupla es una lista que no se puede cambiar. Eso parece una limitación y es justo lo que la hace útil: como no cambia, se puede usar de clave en un diccionario o de elemento en un conjunto, cosa que con una lista es imposible.
Y el desempaquetado —x, y = punto— está por todas partes en Python: es lo que permite que una función devuelva varias cosas, o que un for sobre un diccionario te dé la clave y el valor a la vez.
Diccionarios
stock = {"pan": 3, "uva": 10}
stock["pan"] = 5 # sustituye
stock.get("kiwi") # None, no revienta
stock.get("kiwi", 0) # 0
stock.setdefault("kiwi", 1)
stock["pan"] = stock.get("pan", 0) + 2
for k, v in stock.items(): ...
salida{'pan': 5, 'uva': 10}
get('kiwi') None
get('kiwi', 0) 0
setdefault('kiwi') 1 -> {'pan': 5, 'uva': 10, 'kiwi': 1}
sumar 2 a pan: 7
acceso directo: KeyError 'fantasma'
d["x"] y d.get("x") es la fuente número uno de KeyError. Los corchetes revientan si la clave no está; get devuelve None, o lo que le digas como segundo argumento. Usa corchetes cuando la clave tiene que estar —así el error te avisa de un fallo real— y get cuando puede faltar.Desde Python 3.7 los diccionarios conservan el orden de inserción. Antes no, y aún hay tutoriales que dicen lo contrario.
Conjuntos
a, b = {1,2,3}, {3,4,5}
a | b # unión
a & b # intersección
a - b # diferencia
list(set([1,1,2,3,3]))
salidaunion {1, 2, 3, 4, 5} intersección {3} diferencia {1, 2}
quitar repetidos de [1,1,2,3,3]: [1, 2, 3]
pertenencia en set es instantánea: True
Dos usos que justifican conocerlos: quitar repetidos en una línea, y preguntar si algo está. Ese in sobre un conjunto es instantáneo pase lo que pase, mientras que sobre una lista recorre elemento a elemento. Con mil elementos no se nota; con un millón, sí.
Ojo: {} vacío es un diccionario, no un conjunto. El conjunto vacío es set().
La copia que no copia
original = [[1,2],[3,4]] superficial = original.copy() superficial[0].append(99)
salidaoriginal tras tocar la copia: [[1, 2, 99], [3, 4]]
copy() hace una copia superficial: la lista de fuera es nueva, pero las de dentro son las mismas. Tocar la copia cambia el original. Para que no pase:
import copy profunda = copy.deepcopy(original)
Y esto no es una curiosidad de las listas: es la misma idea de siempre, que una variable guarda una referencia al objeto, no el objeto. Vale igual para los diccionarios anidados.
| Quieres… | Usa |
|---|---|
| Una secuencia que crece | list |
| Algo que no debe cambiar, o una clave | tuple |
| Buscar por clave | dict, y get si puede faltar |
| Quitar repetidos o preguntar si está | set |
| Copiar algo anidado | copy.deepcopy |
| El último elemento | x[-1] |
Todo el código de esta lección se ejecutó con Python 3.14 en un contenedor limpio antes de publicarla; las salidas y los errores están copiados de esa ejecución.