Diccionarios
Diccionarios en Python
Qué es un diccionario
Un diccionario es una colección de pares clave-valor, mutable y sin orden garantizado. Cada elemento tiene una clave única que sirve para acceder a su valor, igual que un diccionario real donde cada palabra tiene su definición.
A diferencia de las listas donde accedes por posición numérica, en los diccionarios accedes por clave, que puede ser cualquier tipo inmutable: string, número o tupla.
python
# Un diccionario básico
alumno = {
"nombre": "Ana García",
"edad": 22,
"nota": 8.5,
"activa": True
}
# Acceso por clave
print(alumno["nombre"]) # Ana García
print(alumno["nota"]) # 8.5
Cómo crear diccionarios
python
# Con llaves
persona = {"nombre": "Ana", "edad": 22}
# Con dict()
persona = dict(nombre="Ana", edad=22)
# Desde lista de tuplas
pares = [("nombre", "Ana"), ("edad", 22)]
persona = dict(pares)
# Diccionario vacío
vacio1 = {}
vacio2 = dict()
# Con dict.fromkeys() — todas las claves con el mismo valor inicial
claves = ["nombre", "edad", "ciudad"]
plantilla = dict.fromkeys(claves, None)
print(plantilla) # {'nombre': None, 'edad': None, 'ciudad': None}
plantilla2 = dict.fromkeys(["a", "b", "c"], 0)
print(plantilla2) # {'a': 0, 'b': 0, 'c': 0}
# Con comprensión de diccionario
cuadrados = {n: n**2 for n in range(1, 6)}
print(cuadrados) # {1: 1, 2: 4, 3: 9, 4: 16, 5: 25}
Acceso a elementos
Acceso directo con []
python
alumno = {"nombre": "Ana", "edad": 22, "ciudad": "Madrid"}
print(alumno["nombre"]) # Ana
print(alumno["edad"]) # 22
# Si la clave no existe lanza KeyError
try:
print(alumno["email"])
except KeyError:
print("La clave 'email' no existe")
.get() — acceso seguro sin errores
python
alumno = {"nombre": "Ana", "edad": 22}
# Sin valor por defecto — devuelve None si no existe
print(alumno.get("nombre")) # Ana
print(alumno.get("email")) # None ← no lanza error
# Con valor por defecto
print(alumno.get("email", "no disponible")) # no disponible
print(alumno.get("edad", 0)) # 22
# Uso práctico
def obtener_nota(alumno, asignatura):
return alumno.get(asignatura, "Sin nota")
notas = {"Matemáticas": 9.0, "Historia": 7.5}
print(obtener_nota(notas, "Matemáticas")) # 9.0
print(obtener_nota(notas, "Física")) # Sin nota
Modificar diccionarios
Añadir y actualizar elementos
python
alumno = {"nombre": "Ana", "edad": 22}
# Añadir nueva clave
alumno["ciudad"] = "Madrid"
alumno["email"] = "ana@mail.com"
print(alumno)
# {'nombre': 'Ana', 'edad': 22, 'ciudad': 'Madrid', 'email': 'ana@mail.com'}
# Actualizar valor existente
alumno["edad"] = 23
print(alumno["edad"]) # 23
.update() — actualizar con varios pares a la vez
python
alumno = {"nombre": "Ana", "edad": 22}
# Con otro diccionario
alumno.update({"ciudad": "Madrid", "email": "ana@mail.com"})
print(alumno)
# Con argumentos clave=valor
alumno.update(edad=23, nota=8.5)
print(alumno)
# Actualizar solo si la clave ya existe no tiene método directo
# pero se puede hacer así
datos_nuevos = {"edad": 24, "telefono": "600123456"}
for clave, valor in datos_nuevos.items():
if clave in alumno:
alumno[clave] = valor # solo actualiza las que existen
.setdefault() — añadir solo si no existe
python
alumno = {"nombre": "Ana", "edad": 22}
# Si la clave existe devuelve el valor actual sin modificarlo
print(alumno.setdefault("nombre", "Carlos")) # Ana ← no cambia
# Si la clave no existe la crea con el valor por defecto
print(alumno.setdefault("ciudad", "Madrid")) # Madrid ← la crea
print(alumno)
# {'nombre': 'Ana', 'edad': 22, 'ciudad': 'Madrid'}
# Uso práctico: acumular en listas
def agrupar_por_ciudad(alumnos):
grupos = {}
for alumno in alumnos:
ciudad = alumno["ciudad"]
grupos.setdefault(ciudad, []).append(alumno["nombre"])
return grupos
alumnos = [
{"nombre": "Ana", "ciudad": "Madrid"},
{"nombre": "Carlos", "ciudad": "Barcelona"},
{"nombre": "María", "ciudad": "Madrid"},
{"nombre": "Pedro", "ciudad": "Barcelona"},
{"nombre": "Lucía", "ciudad": "Valencia"},
]
print(agrupar_por_ciudad(alumnos))
# {'Madrid': ['Ana', 'María'], 'Barcelona': ['Carlos', 'Pedro'], 'Valencia': ['Lucía']}
Métodos para eliminar elementos
.pop() — elimina por clave y devuelve el valor
python
alumno = {"nombre": "Ana", "edad": 22, "ciudad": "Madrid", "email": "ana@mail.com"}
# Elimina y devuelve el valor
email = alumno.pop("email")
print(email) # ana@mail.com
print(alumno) # {'nombre': 'Ana', 'edad': 22, 'ciudad': 'Madrid'}
# Con valor por defecto si no existe
telefono = alumno.pop("telefono", "no tenía teléfono")
print(telefono) # no tenía teléfono ← no lanza error
# Sin valor por defecto y clave inexistente lanza KeyError
try:
alumno.pop("inexistente")
except KeyError:
print("Clave no encontrada")
.popitem() — elimina y devuelve el último par insertado
python
alumno = {"nombre": "Ana", "edad": 22, "ciudad": "Madrid"}
clave, valor = alumno.popitem()
print(clave, valor) # ciudad Madrid ← el último insertado
print(alumno) # {'nombre': 'Ana', 'edad': 22}
.clear() — vacía el diccionario
python
datos = {"a": 1, "b": 2, "c": 3}
datos.clear()
print(datos) # {}
del — elimina por clave
python
alumno = {"nombre": "Ana", "edad": 22, "ciudad": "Madrid"}
del alumno["ciudad"]
print(alumno) # {'nombre': 'Ana', 'edad': 22}
# Eliminar el diccionario completo
del alumno
# print(alumno) # NameError
Métodos para recorrer diccionarios
.keys() — devuelve las claves
python
alumno = {"nombre": "Ana", "edad": 22, "ciudad": "Madrid"}
print(alumno.keys()) # dict_keys(['nombre', 'edad', 'ciudad'])
for clave in alumno.keys():
print(clave)
# nombre
# edad
# ciudad
# Convertir a lista
claves = list(alumno.keys())
print(claves) # ['nombre', 'edad', 'ciudad']
# Comprobar si una clave existe
print("nombre" in alumno.keys()) # True
print("nombre" in alumno) # True ← forma más directa y eficiente
.values() — devuelve los valores
python
alumno = {"nombre": "Ana", "edad": 22, "nota": 8.5}
print(alumno.values()) # dict_values(['Ana', 22, 8.5])
for valor in alumno.values():
print(valor)
# Operaciones sobre valores
notas = {"Matemáticas": 9.0, "Historia": 7.5, "Física": 8.2}
print(max(notas.values())) # 9.0
print(min(notas.values())) # 7.5
print(sum(notas.values()) / len(notas)) # 8.23 ← media
.items() — devuelve pares clave-valor
python
alumno = {"nombre": "Ana", "edad": 22, "ciudad": "Madrid"}
print(alumno.items())
# dict_items([('nombre', 'Ana'), ('edad', 22), ('ciudad', 'Madrid')])
# Desempaquetando en el bucle
for clave, valor in alumno.items():
print(f"{clave}: {valor}")
# nombre: Ana
# edad: 22
# ciudad: Madrid
# Uso práctico: mostrar configuración
config = {
"idioma": "español",
"tema": "oscuro",
"notificaciones": True,
"tamaño_fuente": 14
}
print("=== CONFIGURACIÓN ===")
for ajuste, valor in config.items():
print(f" {ajuste:<20} {valor}")
Copia de diccionarios
python
original = {"nombre": "Ana", "notas": [8.5, 9.0]}
# Asignación — NO es copia, mismo objeto
referencia = original
referencia["nombre"] = "Carlos"
print(original["nombre"]) # Carlos ← también cambia
# Copia superficial
copia1 = original.copy()
copia2 = dict(original)
copia1["nombre"] = "María"
print(original["nombre"]) # Carlos ← no cambia el string
# Pero los objetos mutables internos sí se comparten
copia1["notas"].append(7.5)
print(original["notas"]) # [8.5, 9.0, 7.5] ← afectado
# Copia profunda para diccionarios con objetos mutables
import copy
copia_profunda = copy.deepcopy(original)
copia_profunda["notas"].append(6.0)
print(original["notas"]) # [8.5, 9.0, 7.5] ← intacto
Comprensiones de diccionario
python
# Básica
cuadrados = {n: n**2 for n in range(1, 6)}
print(cuadrados) # {1: 1, 2: 4, 3: 9, 4: 16, 5: 25}
# Con condición
pares = {n: n**2 for n in range(1, 11) if n % 2 == 0}
print(pares) # {2: 4, 4: 16, 6: 36, 8: 64, 10: 100}
# Invertir claves y valores
original = {"a": 1, "b": 2, "c": 3}
invertido = {v: k for k, v in original.items()}
print(invertido) # {1: 'a', 2: 'b', 3: 'c'}
# Transformar valores
precios = {"laptop": 1000, "ratón": 50, "teclado": 120}
con_iva = {producto: round(precio * 1.21, 2)
for producto, precio in precios.items()}
print(con_iva)
# {'laptop': 1210.0, 'ratón': 60.5, 'teclado': 145.2}
# Filtrar por valor
notas = {"Ana": 8.5, "Carlos": 4.8, "María": 9.2, "Pedro": 5.0}
aprobados = {nombre: nota for nombre, nota in notas.items() if nota >= 5}
print(aprobados) # {'Ana': 8.5, 'María': 9.2, 'Pedro': 5.0}
# Desde dos listas
nombres = ["Ana", "Carlos", "María"]
notas = [8.5, 6.0, 9.2]
dict_notas = {nombre: nota for nombre, nota in zip(nombres, notas)}
print(dict_notas) # {'Ana': 8.5, 'Carlos': 6.0, 'María': 9.2}
Diccionarios anidados
python
# Diccionario de diccionarios
alumnos = {
"ana": {
"nombre": "Ana García",
"edad": 22,
"notas": {"Matemáticas": 9.0, "Historia": 7.5},
"ciudad": "Madrid"
},
"carlos": {
"nombre": "Carlos López",
"edad": 20,
"notas": {"Matemáticas": 6.0, "Historia": 8.0},
"ciudad": "Barcelona"
}
}
# Acceso anidado
print(alumnos["ana"]["nombre"]) # Ana García
print(alumnos["ana"]["notas"]["Matemáticas"]) # 9.0
# Modificar valor anidado
alumnos["carlos"]["notas"]["Física"] = 7.5
print(alumnos["carlos"]["notas"])
# {'Matemáticas': 6.0, 'Historia': 8.0, 'Física': 7.5}
# Recorrer diccionario anidado
for id_alumno, datos in alumnos.items():
print(f"\n{datos['nombre']} ({datos['ciudad']})")
for asignatura, nota in datos["notas"].items():
print(f" {asignatura}: {nota}")
Operaciones frecuentes
Fusionar diccionarios
python
dict1 = {"a": 1, "b": 2}
dict2 = {"c": 3, "d": 4}
dict3 = {"b": 99, "e": 5} # "b" duplicada
# Con update (modifica dict1)
resultado = dict1.copy()
resultado.update(dict2)
print(resultado) # {'a': 1, 'b': 2, 'c': 3, 'd': 4}
# Con | (Python 3.9+) — crea nuevo diccionario
fusionado = dict1 | dict2
print(fusionado) # {'a': 1, 'b': 2, 'c': 3, 'd': 4}
# Si hay claves duplicadas, el de la derecha gana
print(dict1 | dict3) # {'a': 1, 'b': 99, 'e': 5}
# Fusionar varios
todos = dict1 | dict2 | dict3
print(todos) # {'a': 1, 'b': 99, 'c': 3, 'd': 4, 'e': 5}
Ordenar un diccionario
python
notas = {"Carlos": 6.0, "Ana": 9.2, "María": 7.5, "Pedro": 5.0}
# Ordenar por clave
por_nombre = dict(sorted(notas.items()))
print(por_nombre)
# {'Ana': 9.2, 'Carlos': 6.0, 'María': 7.5, 'Pedro': 5.0}
# Ordenar por valor ascendente
por_nota_asc = dict(sorted(notas.items(), key=lambda x: x[1]))
print(por_nota_asc)
# {'Pedro': 5.0, 'Carlos': 6.0, 'María': 7.5, 'Ana': 9.2}
# Ordenar por valor descendente
por_nota_desc = dict(sorted(notas.items(), key=lambda x: x[1], reverse=True))
print(por_nota_desc)
# {'Ana': 9.2, 'María': 7.5, 'Carlos': 6.0, 'Pedro': 5.0}
Contar frecuencias
python
palabras = ["python", "es", "genial", "python", "mola", "python", "es"]
# Forma manual
frecuencias = {}
for palabra in palabras:
frecuencias[palabra] = frecuencias.get(palabra, 0) + 1
print(frecuencias)
# {'python': 3, 'es': 2, 'genial': 1, 'mola': 1}
# Con Counter del módulo collections
from collections import Counter
frecuencias = Counter(palabras)
print(frecuencias)
# Counter({'python': 3, 'es': 2, 'genial': 1, 'mola': 1})
print(frecuencias.most_common(2))
# [('python', 3), ('es', 2)]
# Contar caracteres en una palabra
texto = "mississippi"
contador = Counter(texto)
print(contador)
# Counter({'s': 4, 'i': 4, 'p': 2, 'm': 1})
Agrupar elementos
python
from collections import defaultdict
ventas = [
{"producto": "laptop", "ciudad": "Madrid", "importe": 1200},
{"producto": "ratón", "ciudad": "Barcelona", "importe": 45},
{"producto": "teclado", "ciudad": "Madrid", "importe": 120},
{"producto": "monitor", "ciudad": "Barcelona", "importe": 350},
{"producto": "laptop", "ciudad": "Madrid", "importe": 1200},
]
# Agrupar ventas por ciudad
por_ciudad = defaultdict(list)
for venta in ventas:
por_ciudad[venta["ciudad"]].append(venta["importe"])
for ciudad, importes in por_ciudad.items():
total = sum(importes)
print(f"{ciudad}: {importes} → Total: {total} €")
# Madrid: [1200, 120, 1200] → Total: 2520 €
# Barcelona: [45, 350] → Total: 395 €
defaultdict — diccionario con valor por defecto
python
from collections import defaultdict
# Con int — contador automático
contador = defaultdict(int)
palabras = ["ana", "carlos", "ana", "maría", "ana", "carlos"]
for palabra in palabras:
contador[palabra] += 1 # no lanza KeyError aunque no exista
print(dict(contador))
# {'ana': 3, 'carlos': 2, 'maría': 1}
# Con list — agrupador automático
agrupador = defaultdict(list)
datos = [("Madrid", "Ana"), ("Barcelona", "Carlos"), ("Madrid", "María")]
for ciudad, nombre in datos:
agrupador[ciudad].append(nombre)
print(dict(agrupador))
# {'Madrid': ['Ana', 'María'], 'Barcelona': ['Carlos']}
# Con dict — diccionario de diccionarios automático
registro = defaultdict(dict)
registro["ana"]["nota"] = 8.5
registro["ana"]["ciudad"] = "Madrid"
print(dict(registro))
# {'ana': {'nota': 8.5, 'ciudad': 'Madrid'}}
Ejemplo práctico completo — sistema de inventario
python
from collections import defaultdict
def crear_producto(nombre, precio, stock, categoria):
return {
"nombre": nombre,
"precio": precio,
"stock": stock,
"categoria": categoria
}
def añadir_producto(inventario, codigo, producto):
if codigo in inventario:
print(f"El código {codigo} ya existe.")
return False
inventario[codigo] = producto
print(f"✓ '{producto['nombre']}' añadido.")
return True
def actualizar_stock(inventario, codigo, cantidad):
if codigo not in inventario:
print(f"Código {codigo} no encontrado.")
return False
inventario[codigo]["stock"] += cantidad
nombre = inventario[codigo]["nombre"]
nuevo = inventario[codigo]["stock"]
accion = "añadidas" if cantidad > 0 else "retiradas"
print(f"✓ {abs(cantidad)} unidades {accion} de '{nombre}'. Stock: {nuevo}")
return True
def buscar_por_categoria(inventario, categoria):
return {
codigo: producto
for codigo, producto in inventario.items()
if producto["categoria"].lower() == categoria.lower()
}
def productos_stock_bajo(inventario, minimo=5):
return {
codigo: producto
for codigo, producto in inventario.items()
if producto["stock"] <= minimo
}
def valor_total_inventario(inventario):
return sum(
p["precio"] * p["stock"]
for p in inventario.values()
)
def resumen_por_categoria(inventario):
resumen = defaultdict(lambda: {"productos": 0, "valor": 0.0})
for producto in inventario.values():
cat = producto["categoria"]
resumen[cat]["productos"] += 1
resumen[cat]["valor"] += producto["precio"] * producto["stock"]
return dict(resumen)
def mostrar_inventario(inventario):
if not inventario:
print("Inventario vacío.")
return
print(f"\n{'='*62}")
print(f" {'Código':<8} {'Nombre':<20} {'Cat.':<14} {'Precio':>8} {'Stock':>6}")
print(f" {'─'*60}")
for codigo, p in sorted(inventario.items()):
alerta = " ⚠" if p["stock"] <= 3 else ""
print(f" {codigo:<8} {p['nombre']:<20} {p['categoria']:<14} "
f"{p['precio']:>7.2f}€ {p['stock']:>5}{alerta}")
print(f" {'─'*60}")
print(f" Valor total del inventario: {valor_total_inventario(inventario):,.2f} €")
print(f"{'='*62}")
# --- Programa principal ---
inventario = {}
añadir_producto(inventario, "LAP001",
crear_producto("Laptop Pro", 1299.99, 8, "Informática"))
añadir_producto(inventario, "MON001",
crear_producto("Monitor 27\"", 449.99, 12, "Informática"))
añadir_producto(inventario, "TEC001",
crear_producto("Teclado RGB", 129.99, 3, "Periféricos"))
añadir_producto(inventario, "RAT001",
crear_producto("Ratón Inalámb.", 59.99, 25, "Periféricos"))
añadir_producto(inventario, "AUR001",
crear_producto("Auriculares BT", 199.99, 2, "Audio"))
añadir_producto(inventario, "SSD001",
crear_producto("Disco SSD 1TB", 109.99, 15, "Almacenamiento"))
mostrar_inventario(inventario)
actualizar_stock(inventario, "TEC001", -1)
actualizar_stock(inventario, "LAP001", 5)
print("\n⚠ PRODUCTOS CON STOCK BAJO (≤5 unidades):")
bajos = productos_stock_bajo(inventario)
for codigo, p in bajos.items():
print(f" {codigo}: {p['nombre']} → {p['stock']} unidades")
print("\n📦 RESUMEN POR CATEGORÍA:")
resumen = resumen_por_categoria(inventario)
for cat, datos in sorted(resumen.items()):
print(f" {cat:<15} {datos['productos']} producto(s) "
f"Valor: {datos['valor']:>10,.2f} €")
```
Salida:
```
✓ 'Laptop Pro' añadido.
✓ 'Monitor 27"' añadido.
✓ 'Teclado RGB' añadido.
✓ 'Ratón Inalámb.' añadido.
✓ 'Auriculares BT' añadido.
✓ 'Disco SSD 1TB' añadido.
==============================================================
Código Nombre Cat. Precio Stock
────────────────────────────────────────────────────────────
AUR001 Auriculares BT Audio 199.99€ 2 ⚠
LAP001 Laptop Pro Informática 1299.99€ 8
MON001 Monitor 27" Informática 449.99€ 12
RAT001 Ratón Inalámb. Periféricos 59.99€ 25
SSD001 Disco SSD 1TB Almacenamiento 109.99€ 15
TEC001 Teclado RGB Periféricos 129.99€ 3 ⚠
────────────────────────────────────────────────────────────
Valor total del inventario: 28,109.49 €
==============================================================
✓ 1 unidades retiradas de 'Teclado RGB'. Stock: 2
✓ 5 unidades añadidas de 'Laptop Pro'. Stock: 13
⚠ PRODUCTOS CON STOCK BAJO (≤5 unidades):
AUR001: Auriculares BT → 2 unidades
TEC001: Teclado RGB → 2 unidades
📦 RESUMEN POR CATEGORÍA:
Almacenamiento 1 producto(s) Valor: 1,649.85 €
Audio 1 producto(s) Valor: 399.98 €
Informática 2 producto(s) Valor: 22,289.75 €
Periféricos 2 producto(s) Valor: 1,769.71 €
Resumen de métodos
| Método | Qué hace | Devuelve |
|---|---|---|
d[k] |
Accede al valor de clave k | valor o KeyError |
.get(k, def) |
Accede con valor por defecto | valor o def |
.update(d2) |
Actualiza con otro diccionario | None |
.setdefault(k, v) |
Crea clave si no existe | valor actual o v |
.pop(k, def) |
Elimina y devuelve valor de k | valor o def |
.popitem() |
Elimina y devuelve último par | (clave, valor) |
.clear() |
Vacía el diccionario | None |
.copy() |
Copia superficial | dict |
.keys() |
Vista de las claves | dict_keys |
.values() |
Vista de los valores | dict_values |
.items() |
Vista de pares clave-valor | dict_items |
dict.fromkeys(k, v) |
Crea diccionario desde claves | dict |
k in d |
Comprueba si clave existe | bool |
d1 | d2 |
Fusiona dos diccionarios (3.9+) | dict |