Codificar y decodificar JSON

Codificar y decodificar JSON



Wikipedia define JSON de la siguiente manera:

JSON, acrónimo de JavaScript Object Notation, es un formato de texto ligero para el intercambio de datos. JSON es un subconjunto de la notación literal de objetos de JavaScript aunque hoy, debido a su amplia adopción como alternativa a XML, se considera un formato de lenguaje independiente.

Permítaseme agregar que JSON es en la actualidad utilizado por casi todos los servicios web para el envío y recepción de datos.

A partir de la versión 2.6 Python incorpora en su librería estándar el módulo json, con una API similar a la de pickle, para codificar y decodificar información en el formato JSON. “Codificar” y “decodificar” deben ser entendidos como convertir de un objeto Python a JSON y vice-versa.

El formato JSON es bastante similar a la sintaxis de Python, pues contiene únicamente dos tipos de estructuras: diccionarios y listas. Diccionario es lo que en Python conocemos como tal, un conjunto de pares con una clave y un valor. Y una lista no es más que un conjunto ordenado de objetos.

Para ilustrar esto, tomemos como ejemplo el siguiente código.

>>> d = {"sitio": "Recursos Python", "url": "recursospython.com"}

Aquí creamos un simple diccionario con dos pares clave-valor. Para convertirlo a una cadena JSON, utilizamos la función dumps.

>>> import json
>>> json.dumps(d)
'{"url": "recursospython.com", "sitio": "Recursos Python"}'

Si bien el resultado es prácticamente similar, existen algunas diferencias. Por ejemplo, en Python se usa None para indicar un valor vacío o no establecido, pero en JSON se emplea null. Python permite comillas simples, JSON requiere comillas dobles. En Python los valores booleanos son True y False; en JSON, true y false.

>>> json.dumps([None, True, False, 'Hola, mundo!'])
'[null, true, false, "Hola, mundo!"]'

El módulo se encarga de realizar todos esos cambios correctamente. Nótese que el resultado es siempre una cadena (str en Python 3 y unicode en Python 2).

En el formato JSON, un diccionario se conoce con el nombre de objeto, y una lista con el nombre de vector o array. Considerando esto, los objetos que pueden pasarse a la función dumps para ser convertidos a JSON son los siguientes:

  • Diccionarios (dict)
  • Listas y tuplas (list, tuple)
  • Cadenas (str en Python 3, unicode en Python 2)
  • Números (int, float)
  • True, False, y None

Intentar llamar a dumps con un objeto que no puede ser representado como JSON lanzará una excepción del tipo TypeError.

>>> class C:
...     pass
...
>>> json.dumps(C)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  ...
TypeError: <class '__main__.C'> is not JSON serializable

Para decodificar una cadena en el formato JSON (es decir, convertirla a un objeto de Python), utilizamos loads.

>>> data = json.loads('[null, true, false, "Hola, mundo!"]')
>>> data
[None, True, False, 'Hola, mundo!']
>>> data[1]
True
>>> data[3]
'Hola, mundo!'

Otros ejemplos:

>>> d = json.loads('{"url": "recursospython.com", "sitio": "Recursos Python"}')
>>> d["url"]
'recursospython.com'
>>> d["sitio"]
'Recursos Python'

Codificar y decodificar en archivos

Además, el módulo json provee las funciones dump y load, similares a dumps y loads pero que operan con archivos. Por ejemplo, podemos almacenar una lista de Python en un archivo con el formato JSON:

data = [True, False, None, 'Hola, mundo!']
with open("data.json", "w") as f:
   json.dump(data, f)

De forma análoga recuperamos el objeto leyendo el fichero vía load().

with open("data.json") as f:
    data = json.load(f)
# Imprime [True, False, None, 'Hola, mundo!'].
print(data)

De hecho las funciones no se limitan únicamente a archivos del disco, sino que aceptan cualquier objeto que soporte los métodos write() o read().

from io import StringIO
stream = StringIO()
data = [True, False, None, 'Hola, mundo!']
json.dump(data, stream)
print(stream.getvalue())

Otras opciones

Para mostrar una estructura de JSON en formato agradable y legible podemos usar el parámetro indent, que indica la cantidad de espacios que deben emplearse como “indentación”.

>>> data = [True, False, {"site": "Recursos Python"}]
>>> print(json.dumps(data, indent=4))
[
    true,
    false,
    {
        "site": "Recursos Python"
    }
]

Por otro lado, en algunos casos se quiere comprimir lo más posible el resultado. Para esto podemos usar el parámetro separators, que por defecto equivale a (", ", ": "), para remover los espacios entre claves, valores y elementos de la lista.

>>> json.dumps(data, separators=(",", ":"))
'[true,false,{"site":"Recursos Python"}]'

Por último, especificando el parámetro sort_keys, que por defecto es False, logramos ordenar por claves la estructura que resulta de la codificación.

>>> json.dumps({"c": 0, "b": 0, "a": 0}, sort_keys=True)
'{"a": 0, "b": 0, "c": 0}'

¡No olvides chequear la documentación de json para el resto de las opciones!



Deja un comentario