Diccionarios (I)
Colecciones de datos
Aunque ya sabemos algo sobre diccionarios en Python, lo cierto es que en esta subsección de LENGUAJES hemos hablado mucho de listas (y de tuplas) y muy poco de diccionarios, al menos mucho menos de lo que se merece.
Cuando uno comienza a programar en OOo Basic deberá trabajar con listas o arrays. Si después programa en Python lo "lógico" es que traslade su interés al uso las listas. Además las listas en Python son sencillas e intuitivas de usar y muy útiles.
Pero Python es mucho más rico y complejo que OOo Basic también es esto de las colecciones de datos y los diccionarios son también expresión de esa superioridad: un diccionario mejora la organización de los datos y también la velocidad y precisión del acceso, que está en función del significado y no de la posición como en las listas.
Un diccionario es una colección de elementos organizados mediante pares clave → valor (key:value) en la que cada dato-valor (que sí se puede modificar y duplicar) se almacena asociado a una clave única (por lo que es inmutable y única).
persona = {
"nombre": "Ana",
"edad": 34,
"profesion": "Ingeniera"
}
En este caso el diccionario persona consta de tres claves y cada clave contiene un dato o valor. v.g. la clave "nombre" contiene el valor "Ana"
Si estuviéramos trabajando con listas persona = ["Ana", 34, "Ingeniera"] (1), para obtener la profesión deberíamos expresarlo como persona[2], mientras que como diccionario diremos persona["profesion"]. En el caso de las listas, cualquier modificación del contenido implica un cambio en el procedimiento de acceso que deberemos conocer de antemano; en el caso de los diccionarios es suficiente con conocer el nombre de la clave.
Si lo anterior no fuera suficiente motivo para entender las ventajas de los diccionarios sobre las listas, piensa en la cantidad de "objetos" del mundo real que se pueden expresar como diccionarios:
- ejemplo: alumno - identificador - nombre - curso - etapa - centro - resultados académicos - MAD - ...
- Pero también archivo - ruta - tamaño - fecha...
Estos "objetos" y otros muchos se pueden expresar en estructuras clave - valor. Además, Python implementa internamente los diccionarios mediante tablas hash (2), lo que hace que la búsqueda de un elemento por su clave sea, en condiciones normales, extremadamente rápida. En la práctica, acceder a un valor suele realizarse en tiempo constante, independientemente del tamaño del diccionario.
El método más habitual para crear un diccionario consiste en utilizar llaves, como en provincias = {}, instrucción con la que creamos un diccionario vacío que después podemos dotar de contenido, aunque también es posible (y muy frecuente) crear directamente el diccionario definiendo su estructura y contenido, como en este caso...
provincias = {
"Asturias": "Oviedo",
"León": "Leon",
"Cantabria": "Santander"
}
... aunque también se puede crear un diccionario mediante la función dict() - provincias=dict().
# Bien...
provincias = dict(
Asturias="Oviedo",
Leon="León",
Cantabria="Santander"
)
# O también...
provincias = dict([
("Asturias", "Oviedo"),
("León", "León"),
("Cantabria", "Santander")
])
Aunque esta es la forma simple de expresar un diccionario, lo normal es que su contenido sea más complejo. Pensemos, por ejemplo, que creamos el diccionario provincias pero queremos que contenga una colección de datos (capital - población_2025 - peso_sector_primario , peso_sector_secundario, peso_sector_terciario. Ahora ya no hay un ínico dato asociado a la clave, por lo que debemos expresar esta complejidad de otro modo. Y caben dos posibilidades:
- Como lista
provincia:[capital - población_2025 - peso_sector_primario , peso_sector_secundario] - o Como diccionarios anidados
Veamos el desarrollo de ambas posibilidades en un script.
# Valor como lista de valores
provincias = {
"Asturias": ["Oviedo", 1004326, 4.1, 22.7, 73.2],
"León": ["León", 442000, 8.5, 24.3, 67.2],
"Cantabria": ["Santander", 593000, 3.8, 20.6, 75.6]
}
# Valor como diccionario anidado lista:valor
provincias = {
"Asturias": {
"capital": "Oviedo",
"poblacion_2025": 1004326,
"sector_primario": 4.1,
"sector_secundario": 22.7,
"sector_terciario": 73.2
},
"León": {
"capital": "León",
"poblacion_2025": 442000,
"sector_primario": 8.5,
"sector_secundario": 24.3,
"sector_terciario": 67.2
},
"Cantabria": {
"capital": "Santander",
"poblacion_2025": 593000,
"sector_primario": 3.8,
"sector_secundario": 20.6,
"sector_terciario": 75.6
}
}
Aunque la primera formulación parece más sencilla de crear, en realidad su manejo resulta más complicado, por lo que es preferible recurrir a los diccionarios anidados por varias razones que no vamos a analizar aquí. Además, los diccionarios anidados constituyen la representación natural en Python de la estructura de un documento JSON. Esta correspondencia casi directa explica que los diccionarios anidados sean la estructura de datos preferida para trabajar con información procedente de diferentes fuentes, espcialmente con las que se expresan como archivos JSON.
Entre otras ventajas, esto hace posible que...
import json
with open("provincias.json", "w", encoding="utf-8") as archivo:
json.dump(provincias, archivo, ensure_ascii=False, indent=4)
... nos permita almacenar los datos en un documento en formato JSON, el cual podremos visualizar desde bloc de notas.
Como puedes comprobar, el archivo JSON reproduce prácticamente la misma estructura jerárquica que nuestro diccionario. Esta correspondencia es precisamente una de las razones por las que los diccionarios tienen un papel tan importante en Python cuando se trabaja con datos estructurados.
Para realizar el proceso inverso (cargar en Python un archivo JSON) deberemos ejecutar este script:
import json
with open("provincias.json", "r", encoding="utf-8") as archivo:
provincias = json.load(archivo)
Llegados a este punto parece evidente que los diccionarios dan para algo más que una única entrada. Este es un buen momento para reconocerlo y dar por finalizada la actual. Continuará...
1 Esta sería una de las formas en que se podría expresar lo mismo como lista. Pero no es la única. Personalmente, para casos como ese, yo previero usar un procedimiento multilista (una por "campo") y trabajar después con procedimientos de acceso basados precisamente en las posiciones de los elementos de cada una de ellas.
2 Sin entrar en explicaciones que poco nos aportan aquí, una tabla hash es una estructura de datos que utiliza una función hash para transformar una clave arbitraria en un índice numérico que determina dónde se almacenará o buscará el dato asociado dentro de una tabla. Esto hace que se puedan localizar los datos igual de rápido con independencia del tamaño del diccionario (tiempo constante o O(1)), ya que evita la búsqueda secuencial.