Python recientemente ha venido anunciando algunas características muy interesantes en sus lanzamientos actuales e incluso a futuro, en este artículo mencionaré algunos de los que más me han gustado y el porqué, adicionando también un poco de código que nunca esta de mas
python 3.9
type hinting "nativo", los types hinting es una forma práctica de utilizar tipado estático en python sin embargo para utilizar tipos de datos como list y dict se debía utilizar esto generaba duplicidad y ademas generaba un poco de confusión con los nuevos programadores que lo querían usar (los que llegaron a python por su tipado dinámico no tienen que preocuparse, no será obligatorio usarlo o si? ver Figura 1)
podemos ver en el siguiente código como es la nueva implementación del list agregado de manera nativa
class Book:
def __init__(self,title:str) -> None:
pass
def get_books()->list[Book]:
books = [Book("Misery"), Book("A song of ice and fire")]
return books
print(get_books())
como debía trabajarse en versiones < 3.9
from typing import List
class Book:
def __init__(self,title:str) -> None:
pass
def get_books()->List[Book]:
books = [Book("Misery"), Book("A song of ice and fire")]
return books
print(get_books())
como se aprecia utilizamos List del módulo typing que es una versión genérica de list adicionalmente mypy ya tiene el soporte para poder realizar validaciones de los tipos estáticos (también soporta algunos tipos como List y Dict pero los trata como legacy) como se aprecia en la Figura 2 donde cambio el tipo de return a un str para validarlo como se aprecia en el código
def get_books()->list[Book]:
books = [Book(title="Misery"), Book(title="A song of ice and fire")]
return "test"
python 3.10
Pattern Matching Esta es una feature que realmente me interesa usar en producción, el release oficial está para octubre de este año. Cuando tenía que trabajar en java y python al mismo tiempo a veces extrañaba usar el switch case, este es una versión de este concepto pero con muchisimas mas mejoras, de hecho en varios lenguajes como scala y rust ya se implementa y en python lleva un buen tiempo ya debatiéndose la implementación, el concepto muy resumido es hacer match de un variable por medio de un patrón dado, a diferencia de switch que generalmente es una simple comparación, a continuación tenemos un ejemplo sencillo
def http_error(status):
match status:
case 400:
return "Bad request"
case 404:
return "Not found"
case 418:
return "I'm a teapot"
case _:
return "Something's wrong with the Internet"
http_error()
podemos ver un ejemplo un poco más elaborado donde aplicamos varios conceptos
def validate_user(user_info:tuple):
match user_info:
case ("",""):
print("not enough information is being provided")
case (name,""):
print("do not you have a last name?")
case ("", last_name):
print("do not you have a name?")
case (name, last_name):
print(f"Success {name} {last_name}")
case _:
raise ValueError("Not User")
validate_user(("jairo","andres"))
la salida por consola sería la siguiente
Success jairo andres
en el código la función match lo que realiza es algo llamado un desempaquetamiento de variable y guarda su valor para trabajar en el contexto del case, pero aquí viene lo interesante y es que en el caso anterior al tener una variable tipo tupla la desempaqueta y permite trabajar con los valores que vienen en sus posiciones
(name,last_name) = user_info
con ello aquí entra la diferencia entre un switch case que es algo más superficial y el match pattern que permite validar situaciones más elaboradas
python 3.11
tracebacks mejorados, actualmente python tiene para mi un pequeño inconveniente con el tema de la trazabilidad de los errores y es que en los logs tanto como en los errores que se muestran en consola la línea donde ocurre el error te lo marca pero.. bueno una línea de código puede tener varias instrucciones, al ser python un lenguaje de tipado dinámico a veces esta línea puede ser difícil de leer, veamos un ejemplo actual
def calculate(a,b,c,d,e,f):
result = (a/b/c)*(d/e/f)
calculate(1,2,3,4,0,5)
si ejecutamos tendremos un error similar al siguiente
Traceback (most recent call last):
File "main.py", line 12, in <module>
calculate(1,2,0,4,2,5)
File "main.py", line 10, in calculate
result = (a/b/c)*(d/e/f)
ZeroDivisionError: division by zero
el error es claro, sin embargo no hay claridad en cual de toda la linea anterior sucede el error, es decir en cual operación exacta sucede la división por 0, con la mejora que realmente me parece super buena se vería de la siguiente el error
Traceback (most recent call last):
File "calculation.py", line 54, in <module>
result = (a / b / c) * (d / e / f)
~~~~~~^~~
ZeroDivisionError: division by zero
aquí nos indica que el error ocurre en la división de la variable c por lo tanto ya se puede encontrar el error de una manera más exacta, funciona muy bien también con los diccionarios
Traceback (most recent call last):
File "test.py", line 2, in <module>
x['a']['b']['c']['d'] = 1
~~~~~~~~~~~^^^^^
TypeError: 'NoneType' object is not subscriptable
En el código anterior es un diccionario que en su clave 'c' está devolviendo none entonces se puede verificar si esta mal la key o es que en su valor tiene None, pero ya con esto se tiene más claro donde ocurre y no un error más genérico de que algún valor es none pero no se sabe exactamente cual. Aunque aún debemos esperar ya que la fecha de lanzamiento para este release esta dadas para 2022
Conclusiones
Actualmente python en mi opinión viene haciendo cambios que están interesantes y que complementan bastante a los programadores, de alguna manera están escuchando a la comunidad y sus requerimientos hay algunas promesas para mejoras a futuro en cuanto a rendimiento lo cual genera también un "hype" sobre lo que se viene, por ahora según un tweet de su propio creador podemos tener certeza de que si hay un cambio de un python 3 a un 4 no será tan conflictivo como lo fue de la 2 ala 3