Estoy usando mal los type annotations?
Los type annotations son una caracteristica bastante interesante agregada en python apartir de la version 3.5, la cual nos permite agregar tipos de datos tanto como a funciones, clases y variables estos tipos de datos no afectan el rendimiento y son muy usados junto con otras herramientas de validacion como mypy.
A la hora de desarrollar proyectos en python enfocados al scripting utilizar el tipado dinamico es un gran ventaja y esta bien, pero en proyectos grandes en donde existen validaciones, logica de negocio, casos de uso y mucho codigo modificado por diferentes programadores empieza a tonarse dificil entender que recibe una fucnion, que retorna una funcion etc, por eso estas caracteristicas en grandes proyectos son muy importantes veamos un ejemplo en codigo:
def greeting(name: str) -> str:
return 'Hello ' + name
En la funcion anterior estamos especificando que la funcion greeting recibe un parametro string y esto retorna una concatenacion, esto esta muy bien por que ademas en visual studio code y otros editores agregan autocomplete a estas funciones y variables, esto funciona igual para cualquier tipo de dato de python como puede ser bool, int, float,date,list,dict (list y dict fueron agregados recientemente para usarse sin ninguna herramienta adicional en python 3.9) ok ahora veamos un ejemplo en donde no estariamos usando del todo bien esta caracteristica
Tendremos una archivo llamado persona.json para este caso pero puede ser una llamada a una API en donde devuelva el json como se muestra acontinuacion
{
"name":"Pedro Jose",
"age":20,
"birthday":"2000-11-09"
}
Para cargar esta informacion realizamos el siguiente codigo en python (para los ejemplos de codigo usare python 3.7)
import json
persona = {}
with open("persona.json") as persona_json:
persona = json.load(persona_json)
En el codigo anterior abrimos el archivo persona.json lo cargamos utilizando la libreria json a memoria y esto lo convierte a un diccionario, este codigo es un codigo comun usado en python con su tipado dinamico, pero ahora tranformaremos ese mismo codigo utilizando type annotations y nos quedaria de la siguiente forma
import json
from typing import Dict
persona:Dict = {}
def open_persona_file()->Dict:
with open("persona.json") as persona_json:
result_persona = json.load(persona_json)
return result_persona
persona = open_persona_file()
En este caso si yo quisiera acceder a un dato del diccionario que me retorna esta funcion open_persona_file() lo accederia de la siguiente manera
persona["name"]
persona["age"]
persona["birthday"]
Este codigo no esta mal, por que de alguna manera se esta segmentando el tipo de dato que retorna, ya sabemos que es un diccionario y tenemos todas sus propiedades y metodos disponibles para usar, el "problema" viene cuando no se pueden ver que atributos contiene este diccionario, suponiendo por ejemplo que ya no es un archivo que se puede abrir si no una API de un tercero (suponiendo que esta mal documentada, y en codigo tampoco quedaron los campos que se reciben) en este caso si bien se usa las annotations no se estan usando de la mejor manera, lo ideal para tambien estar en este concepto del "autodocumentado del codigo" podriamos hacer la siguiente modificacion
import json
from datetime import date
from typing import Dict
from pydantic import BaseModel
class Persona(BaseModel):
name:str
age:int
birthday:date
persona:Persona
def open_persona_file()->Persona:
with open("persona.json") as persona_json:
result_persona = Persona(**json.load(persona_json))
return result_persona
persona = open_persona_file()
En este caso he agregado una libreria adicional conocida como pydantic es una libreria que ayuda a la validacion y complementa el uso de las type notations, y que porcierto recientemente supero en estrellas de github a su competencia mas cercana
siguiendo con el codigo en este caso se crea una clase llamada Persona la cual contiene los atributos que retorna el archivo .json (autodocumentacion de codigo) luego de esto se cambia el tipo de dato que retorna de tipo Dict a tipo de clase Persona como se aprecia en el siguiente segmento de codigo
def open_persona_file()->Dict: #antigua
def open_persona_file()->Persona: #nueva
dentro del metodo se carga el json pero ya no se retorna el archivo cargado si no se utiliza para crear un objeto de tipo Persona, ya que pydantic permite la creaccion de objetos apartir de diccionarios, este automaticamente realiza tambien validaciones y conversiones en este caso convierte el atributo birthday a tipo date
result_persona = Persona(**json.load(persona_json))
con estos cambios realizados, ahora para acceder a los atributos del archivo .json seria algo como esto
persona.name
persona.age
persona.birthday
pero lo mas interesante es el autocompletar que nos ahorra entre muchos posibles erorres digitar mal el atributo, poner un atributo que no existe o no saber que atributos contiene
adicional al ver los atributos que contiene, podemos tambien tener autocompletado por cada atributo dependiendo del tipo que definimos, en este caso name al ser string tiene unos metodos propios que podemos ver acontinuacion
todo esto puede ser potenciado con librerias externas como por ejemplo mypy que ya mencione en el inicio del articulo, en general estas caracteristicas de python son muy buenas y a medida que las usemos de una mejor manera lograremos mayores beneficios.