Diccionarios
Los diccionarios en Python presentan las siguientes características fundamentales:
- Acceso mediante claves en lugar de índices: Los diccionarios asocian valores a través de claves, permitiendo recuperar elementos utilizando dichas claves como identificadores
- Colección no ordenada de objetos diversos: A diferencia de las listas, los elementos almacenados en un diccionario no mantienen un orden específico. internamente, Python maneja los elementos de manera pseudoaleatoria para optimizar la velocidad de búsqueda
- Estructura mutable y anidada: Los diccionarios pueden crecer o reducirse en su ubicación original, aceptan cualquier tipo de objeto como valor y soportan anidación arbitraria. Cada clave se associa con un único valor, aunque un mismo valor puede estar asociado a múltiples claves
- Tipo mapeable mutable: Los diccionarios permiten modificaciones directas mediante asignación a través de claves
- Tabla de referencias a objetos (tabla hash): Los diccionarios funcionan como tablas de objetos sin orden que soportan acceso por clave. Implementen internamente un algoritmo de hash para la localización de claves, almacenando referencias a objetos de manera similar a las listas
Operaciones y literales comunes con diccionarios
Aplicaciones prácticas de diccionarios
3.1 Operaciones fundamentales
>>> datos = {'temperatura': 25, 'humedad': 60, 'presion': 1013}
>>> datos
{'temperatura': 25, 'humedad': 60, 'presion': 1013}
>>> datos['temperatura'] # Acceso mediante clave
25
El orden interno de las claves generalmente difiere del orden de inserción (desde Python3.7, los diccionarios mantienen el orden de inserción de las claves)
La función incorporada len retorna la cantidad de elementos almacenados en el diccionario
El operador de pertenencia in verifica la existencia de una clave
El método keys devuelve todas las claves del diccionario como un objeto iterable dict_keys
>>> len(datos)
3
>>> 'humedad' in datos
True
>>> datos.keys()
dict_keys(['temperatura', 'humedad', 'presion'])
>>> list(datos.keys())
['temperatura', 'humedad', 'presion']
3.2 Modificación de diccionarios in situ
Los diccionarios son tipos mutables, por lo que permiten modificaciones directas.
Asignar un valor a una clave existente modifica su valor asociado. Asignar a una nueva clave crea un nuevo par clave-valor
La sentencia del elimina un par clave-valor específico
>>> datos
{'temperatura': 25, 'humedad': 60, 'presion': 1013}
>>> datos['humedad'] = ['alta', 'media', 'baja'] # Modificar valor de una clave
>>> datos
{'temperatura': 25, 'humedad': ['alta', 'media', 'baja'], 'presion': 1013}
>>> del datos['presion'] # Eliminar par clave-valor
>>> datos
{'temperatura': 25, 'humedad': ['alta', 'media', 'baja']}
>>> datos['viento'] = 'Noroeste' # Agregar nuevo par clave-valor
>>> datos
{'temperatura': 25, 'humedad': ['alta', 'media', 'baja'], 'viento': 'Noroeste'}
3.3 Métodos adicionales del diccionario
Los métodos keys, values e items retornan objetos iterables que contienen respectivamante todas las claves, todos los valores y todas las tuplas (clave, valor)
>>> datos = {'temperatura': 25, 'humedad': 60, 'presion': 1013}
>>> datos.keys()
dict_keys(['temperatura', 'humedad', 'presion'])
>>> list(datos.keys())
['temperatura', 'humedad', 'presion']
>>> datos.values()
dict_values([25, 60, 1013])
>>> list(datos.values())
[25, 60, 1013]
>>> datos.items()
dict_items([('temperatura', 25), ('humedad', 60), ('presion', 1013)])
>>> list(datos.items())
[('temperatura', 25), ('humedad', 60), ('presion', 1013)]
Se puede utilizar la notación de corchetes [] para obtener valores por clave. Si la clave no existe, se lanza una excepción KeyError. El método get proporciona una alternativa más segura, permitiendo especificar un valor predeterminado que se retorna cuando la clave no existe (por defecto es None)
>>> datos = {'temperatura': 25, 'humedad': 60, 'presion': 1013}
>>> datos['temperatura']
25
>>> datos['aire']
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
KeyError: 'aire'
>>> datos.get('temperatura')
25
>>> print(datos.get('aire')) # Retorna None si no se especifica default
None
>>> datos.get('aire', 80) # Retorna el valor default especificado
80
El método setdefault permite obtener el valor de una clave. Si la clave no existe, la crea con el valor predeterminado proporcionado y retorna dicho valor. Si la clave ya existe, retorna su valor actual
>>> datos = {'temperatura': 25, 'humedad': 60, 'presion': 1013}
>>> datos.setdefault('temperatura', 0)
25
>>> datos.setdefault('aire', 0)
0
>>> datos
{'temperatura': 25, 'humedad': 60, 'presion': 1013, 'aire': 0}
El método D1.update(D2) fusiona el diccionario D2 en D1: las claves presentes solo en D2 se agregan a D1, mientras que las claves comunes se sobrescriben con los valores de D2
>>> datos = {'temperatura': 25, 'humedad': 60, 'presion': 1013}
>>> dict1 = {'temperatura': 25, 'humedad': 60, 'presion': 1013}
>>> dict2 = {'aire': 85, 'humedad': 55}
>>> dict1.update(dict2)
>>> dict1
{'temperatura': 25, 'humedad': 55, 'presion': 1013, 'aire': 85}
El método pop elimina una clave especificada y retorna su valor asociado. El método popitem elimina el último par clave-valor según el orden de inserción. El método clear elimina todos los pares clave-valor del diccionario
>>> datos = {'temperatura': 25, 'humedad': 55, 'presion': 1013, 'aire': 85}
>>> datos.pop('aire')
85
>>> datos
{'temperatura': 25, 'humedad': 55, 'presion': 1013}
>>> datos
{'temperatura': 25, 'humedad': 55, 'presion': 1013}
>>> datos.popitem()
('presion', 1013)
>>> datos
{'temperatura': 25, 'humedad': 55}
>>> datos.clear()
>>> datos
{}
3.4 Iteración sobre diccionarios
>>> peliculas = {'El Santo': '1952',
... 'Rey de Reyes': '1961',
... 'La Gran Familia': '1963'}
>>> for titulo in peliculas:
... print(titulo + '\t' + peliculas[titulo])
...
El Santo 1952
Rey de Kings 1961
La Gran Familia 1963
Para iterable sobre un diccionario, se puede utilizar for clave in diccionario o for clave in diccionario.keys()
Uso de tuplas como claves
Las tuplas pueden utilizarse como claves de diccionario para implementar matrices disperssa
>>> matriz = {}
>>> matriz[(1, 2, 3)] = 77
>>> matriz[(4, 5, 6)] = 88
>>> matriz
{(1, 2, 3): 77, (4, 5, 6): 88}
# Solo se almacenan los valores definidos, el resto permanece vacío
Manejo de claves inexistentes
- Verificar existencia con sentencia if
>>> if (1, 2, 4) in matriz:
... print(matriz[(1, 2, 4)])
...
- Capturar excepción con sentencia try
>>> try:
... print(matriz[(1, 2, 4)])
... except KeyError:
... print(0)
...
0
- Utilizar el método get con valor predeterminado
>>> matriz.get((1, 2, 4), 0)
0
Anidación de diccionarios
>>> registro = {'nombre': 'Carlos',
... 'empleos': ['desarrollador', 'director'],
... 'sitio': 'www.carlosweb.com',
... 'residencia': {'ciudad': 'Trabajando', 'codigo': 543210} }
KeyError: 'puesto'
>>> registro['empleos'][0]
'desarrollador'
>>> registro['residencia']['ciudad']
'Trabajando'
3.5 Métodos alternativos para crear diccionarios
- Definir el diccionario mediante literales
>>> D = {'nombre': 'Carlos', 'edad': 35}
>>> D
{'nombre': 'Carlos', 'edad': 35}
- Crear diccionario vacío y agregar elementos dinámicamente
>>> D = dict()
>>> D
{}
>>> D['nombre'] = 'Carlos'
>>> D['edad'] = 35
>>> D
{'nombre': 'Carlos', 'edad': 35}
- Utilizar la forma de argumentos de palabra clave del constructor dict
>>> D = dict(nombre='Carlos', edad=35)
>>> D
{'nombre': 'Carlos', 'edad': 35}
- Utilizar el constructor dict con secuencia de tuplas (clave, valor)
>>> D = dict([('nombre', 'Carlos'), ('edad', 35)])
>>> D
{'nombre': 'Carlos', 'edad': 35}
Esta forma frecuentemente se combina con la función zip, que combina múltiples iterables en tuplas
>>> claves = ['nombre', 'edad']
>>> valores = ['Carlos', 35]
>>> D = dict(zip(claves, valores))
>>> D
{'nombre': 'Carlos', 'edad': 35}
- Utilizar el método de clase
dict.fromkeys()
dict.fromkeys(iter iterable, valor=None)
El método fromkeys crea un nuevo diccionario donde todas las claves provienen de un iterable y tienen el mismo valor (por defecto None)
>>> dict.fromkeys(['x', 'y'], 0)
{'x': 0, 'y': 0}
- Utilizar comprensión de diccionarios
>>> D = dict(zip(['a', 'b', 'c'], [1, 2, 3]))
>>> D
{'a': 1, 'b': 2, 'c': 3}
>>> D = {k:v for (k, v) in zip(['a', 'b', 'c'], [1, 2, 3])}
>>> D
{'a': 1, 'b': 2, 'c': 3}
>>> D = {x: x ** 2 for x in [1, 2, 3, 4]}
>>> D
{1: 1, 2: 4, 3: 9, 4: 16}
>>> D = {c: c * 4 for c in 'SAL'}
>>> D
{'S': 'SSSS', 'A': 'AAAA', 'L': 'LLLL'}
>>> D = {c.lower(): c + '?' for c in ['SAL', 'HUEVO', 'JAMON']}
>>> D
{'sal': 'SAL?', 'huevo': 'HUEVO?', 'jamon': 'JAMON?'}
3.6 Vistas de diccionario
Los métodos keys, values e items retornan objetos de tipo vista. Las vistas de diccionario son objetos iterables que mantienen el orden de inserción del diccionario, aunque no soportan indexación
>>> D = {'temperatura': 25, 'humedad': 60, 'presion': 1013}
>>> D.keys()
dict_keys(['temperatura', 'humedad', 'presion'])
>>> list(D.keys())
['temperatura', 'humedad', 'presion']
>>> D.values()
dict_values([25, 60, 1013])
>>> list(D.values())
[25, 60, 1013]
>>> D.items()
dict_items([('temperatura', 25), ('humedad', 60), ('presion', 1013)])
>>> list(D.items())
[('temperatura', 25), ('humedad', 60), ('presion', 1013)]
Vistas de diccionario y conjuntos
La vista de claves se comporta de manera similar a un conjunto (ya que las claves son únicas) y soporta operaciones de conjunto. La vista de valores no se comporta como conjunto (los valores pueden repetirse). La vista de items también puede comportarse como conjunto si las tuplas (clave, valor) son únicas e inmutables
>>> D = {'x': 10, 'y': 20, 'z': 30}
>>> K = D.keys()
>>> V = D.values()
>>> I = D.items()
>>> K, V, I
(dict_keys(['x', 'y', 'z']), dict_values([10, 20, 30]), dict_items([('x', 10), ('y', 20), ('z', 30)]))
>>> K | {'w': 40}
{'w', 'z', 'x', 'y'}
>>> V & {'w': 40}
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: unsupported operand type(s) for &: 'dict_values' and 'dict'
>>> K & {'y'}
{'y'}
>>> I | D
{('x', 10), ('z', 30), 'y', 'z', 'x', ('y', 20)}
>>> I | {('w', 40)}
{('w', 40), ('x', 10), ('z', 30), ('y', 20)}
Ordenamiento de claves de diccionario
Los objetos dict_keys no tienen método sort. Para ordenar las claves, se puede utilizar la función incorporada sorted o convertir la vista a lista y usar el método sort
# Convertir a lista y usar el método sort
>>> D = {'z': 3, 'a': 1, 'b': 2}
>>> claves = list(D.keys())
>>> claves
['z', 'a', 'b']
>>> claves.sort()
>>> claves
['a', 'b', 'z']
>>> for k in claves: print(k, D[k])
...
a 1
b 2
z 3
# Utilizar la función sorted
>>> for k in sorted(D.keys()): print(k, D[k])
...
a 1
b 2
z 3