Anuncios

Bienvenidos sean a este post, hoy veremos como hacer la codificacion/decodificacion pero mas personalizado por medio de JSON.

Anuncios

Cuando hablamos de codificacion/decodificacion nos referimos a serializacion/deserializacion de una informacion, tal como vimos en el post anterior, o lo mismo que decir enviar y recibir informacion desde JSON, vamos a ver nuestro primer ejemplo, para ello primero importaremos esto:

>>> import json
Anuncios

Con nuestra herramienta importada vamos a crear la siguiente clase:

>>> class CodificadorComplejo(json.JSONEncoder):
...     def default(self, obj):
...             if isinstance(obj, complex):
...                     return { '_meta' : '_complejo',
...                             'num' : [obj.real, obj.imag],
...                     }
...             return json.JSONEncoder.default(self, obj)
... 
>>>
Anuncios

Esta clase la usaremos para codificar un numero complejo, este recibe un valor de la clase JSONEncoder, luego definiremos un metodo llamado default el cual lo usaremos para todos los objetos recibidos en obj, pasara objeto por objeto hasta que en un momento se encontrara con un numero complejo y cuando se de el caso procedera a devolver el diccionario con esa identificacion y el numero complejo, de lo contrario siempre apilara los objetos procesados, vamos a probarlo y para ello crearemos un objeto:

>>> datos = {
...     'un_int' : 44,
...     'un_complejo' : 3 + 4j,
...     'un_float' : 3.14159265,
... }
>>>
Anuncios

Un objeto simple donde almacenamos tres datos, uno de tipo int, otro complejo y uno de tipo float, nuestro siguiente paso sera procesarlo de la siguiente manera:

>>> datos_json = json.dumps(datos, cls=CodificadorComplejo)
Anuncios

Con esto codificamos o serializamos nuestro objeto, veamos que sucede al mostrarlo:

>>> print(datos_json)
{"un_int": 44, "un_complejo": {"_meta": "_complejo", "num": [3.0, 4.0]}, "un_float": 3.14159265}
>>>
Anuncios

Observen como dentro de nuestro diccionario hemos agregado el caso particular de los numeros complejos, con todo esto realizado pasemos a crear una nueva funcion:

>>> def conectar_objeto(obj):
...     try:
...             if obj['_meta'] == '_complejo':
...                     return complex(*obj['num'])
...     except (KeyError, TypeError):
...             return obj
... 
>>>
Anuncios
Anuncios

Aqui tenemos una funcion que usaremos para conectar a nuestros objetos, dentro tenemos un bloque try/except que es similar al try/catch de otros lenguajes, en el bloque try evaluaremos un codigo y ante cualquier eventualidad o error el except se encarga de procesarlos,en nuestro codigo durante el try evaluaremos si el campo _meta dentro de obj es igual a _complejo y en caso de ser verdadero devolvera la parte numerica del objeto complejo, el except tiene la clave del error y el tipo de error pero en lugar de mostrar una notificacion de error nos devuelve el valor de obj pero lo genial es que no se detendra, solo nos resta probarlo pero primero debemos crear el objeto:

>>> datos_sal = json.loads(datos_json, object_hook=conectar_objeto)
Anuncios

En este caso usamos a loads pasamos el dato generado en datos_json y luego una pequeña funcion llamada object_hook al cual le pasaremos la funcion antes creada.

object_hook es una función opcional que se llamará con el resultado de cualquier objeto literal decodificado (un dict) y este utilizará el valor de retorno de object_hook en lugar del dict.

El Tinchicus
Anuncios

Con nuestro nuevo objeto creado procedamos a mostrarlo:

>>> print(datos_sal)
{'un_int': 44, 'un_complejo': (3+4j), 'un_float': 3.14159265}
>>>
Anuncios

Como pueden ver ahora tenemos una salida mas similar para nuestro numero complejo, con esto vimos una base de como trabajar con un codificador/decodificador personalizado pero vamos a complicarlo un poco mas manejando las fechas, para ello primero importaremos los siguientes modulos y clases:

>>> import json
>>> from datetime import datetime, timedelta, timezone
Anuncios

Primero importaremos a json, como siempre, luego importaremos tres herrmientas para trabajar con las fechas y horas o mejor conocido como datetime, nuestro siguiente paso sera crear dos objetos:

>>> ahora = datetime.now()
>>> ahora_zh = datetime.now(tz=timezone(timedelta(hours=-3)))
Anuncios

El primero sera para almacenar la hora y fecha actual, luego haremos lo mismo pero junto a la zona horaria (timezone) para ello usamos a tz para almacenarlo y timedelta para informar la diferencia horaria, en el caso de mi pais es -3, a continuacion vamos a crear una nueva clase:

>>> class CodificarFecha(json.JSONEncoder):
...     def default(self, obj):
...             if isinstance(obj, datetime):
...                     try:
...                             off = obj.utcoffset().seconds
...                     except AttributeError:
...                             off = None
...                     return {
...                             '_meta' : '_fecha',
...                             'dato' : obj.timetuple()[:6] +
...                                     (obj.microsecond, ),
...                             'utcoffset' : off,
...                     }
...             return json.JSONEncoder.default(self, obj)
... 
>>>
Anuncios
Anuncios

Este es muy similar al anterior, volvemos a usar un atributo de tipo JSONEncoder, volvemos a tener un default para todos los objetos que pasemos, dentro volvemos a usar un condicional para verificar si es una instancia, despues tenemos un bloque try/except donde crea una nueva variable llamada off donde usara utcoffset (funcion que calcula la diferencia entre nuestro tiempo y el de utc) para obtener los segundos de este, pero si este atributo no existe genera una excepcion (error) y procede asignar a off el valor None porque no corresponde, luego devolveremos un valor donde dice que es una fecha, el dato del tiempo y el offset que creamos anteriormente, por ultimo devolvemos el objeto informado en caso de no cumplirse la condicion anterior, para probarlo vamos a hacer lo siguiente:

>>> datos = {
...     'un_int' : 44,
...     'un_float' : 3.14159265,
...     'una_fecha' : ahora,
...     'una_fecha_zh' : ahora_zh,
... }
>>>
Anuncios

Vamos a crear una nuevo objeto de tipo dict con distintos valores, dos de tipo numerico y dos de tipo datetime, nuestro siguiente paso sera serializarlo:

>>> datos_json = json.dumps(datos, cls=CodificarFecha)
Anuncios

Nuestro siguiente paso sera ver como quedo nuestro objeto:

>>> print(datos_json)
{"un_int": 44, "un_float": 3.14159265, "una_fecha": {"_meta": "_fecha", "dato": [2021, 4, 15, 19, 13, 37, 663700], "utcoffset": null}, "una_fecha_zh": {"_meta": "_fecha", "dato": [2021, 4, 15, 19, 14, 26, 506511], "utcoffset": 75600}}
>>>
Anuncios

Vean como nos pasa los datos numericos como aparecen pero en el caso de las fechas nos hizo la misma modificacion que vimos en el ejemplo anterior, pero podemos mejorarlo con la funcion object_hook, para ello crearemos la siguiente funcion:

>>> def conectar_objeto(obj):
...     try:
...             if obj['_meta'] == '_fecha':
...                     if obj['utcoffset'] is None:
...                             zh = None
...                     else:
...                             zh = timezone(timedelta(
...                             seconds=obj['utcoffset']))
...                     return datetime(*obj['dato'], tzinfo=zh)
...     except (KeyError, TypeError):
...             return obj
... 
>>>
Anuncios
Anuncios

Este es muy parecido al conectar_objeto anterior pero con unas sutiles diferencias, tenemos otro try/except pero dentro del try volvemos a usar un condicional para buscar la identidad _fecha en el campo _meta, luego chequeamos si utcoffset es None establece a zh como None de lo contrario establece los segundos de esta zona horaria en zh,, por ultimo devolvemos la fecha en obj y la informacion de la zona horaria, despues de todo esto tenemos el except donde devuelve el objeto en caso de fallar lo anterior, con esto podemos probarlo pero antes decodifiquemos con el object_hook tal como vimos en el ejemplo anterior:

datos_sal = json.loads(datos_json, object_hook = conectar_objeto)
Anuncios

Con nuestro dato decodificado podemos pasar a mostrarlo:

>>> print(datos_sal)
{'un_int': 44, 'un_float': 3.14159265, 'una_fecha': datetime.datetime(2021, 4, 15, 19, 13, 37, 663700), 'una_fecha_zh': datetime.datetime(2021, 4, 15, 19, 14, 26, 506511, tzinfo=datetime.timezone(datetime.timedelta(seconds=75600)))}
>>>
Anuncios

Con todo esto vimos como manejar horas y fechas por medio de JSON, tambien vemos como pudimos crear otra codificador/decodificador personalizado.

Anuncios

En resumen, hoy hemos visto como crear codificadores y decodificadores personalizados, hemos visto como hacer uno para manejar numeros complejos, despues como lo pudimos mejorar a traves de object_hook y por ultimo volvimos a hacer lo mismo pero con le manejo de fechas y horas incluidas zonas horarias, espero les haya sido util sigueme en tumblr, Twitter o Facebook para recibir una notificacion cada vez que subo un nuevo post en este blog, nos vemos en el proximo post.

Anuncios

Donación

Es para mantenimento del sitio, gracias!

$1.50