miércoles, 16 de diciembre de 2020

Python: simular tipado estático mediante anotaciones de tipo.

A mayo del 2020 Python se ubica en el tercer puesto del Index TIOBE que postula un listado de los lenguajes de programación más populares del mundo. Su sintaxis fácil de escribir y su tipado dinámico hacen de Python un lenguaje muy flexible en el desarrollo de todo tipo de aplicaciones.

Ahora bien, su tipado dinámico puede generar diversas discusiones entre programadores por los errores que suele generar al momento de compilar el código. Este tipo de errores se puede mitigar utilizando buenas prácticas al momento de codificar, la página oficial de Python nos ofrece un apartado muy interesante sobre el Annotation Type o Anotaciones de Tipo en español.

Las anotaciones de tipo nos permiten definir anotaciones en nuestro código para que este sea claro y fácil de entender para otros programadores que acostumbran utilizar el tipado estático.

Las anotaciones de tipo pueden ser usadas a partir de la versión 3.6 de Python.

Podemos utilizar estas anotaciones en:

1. Variables

Para las variables solo basta escribir el nombre de la variable seguido dos puntos y especificar el tipo. También es posible definir el tipo sin necesidad de inicializar la variable.

a : int = 12
b : float = 15.5
c : bool = True
d : str = 'Python'

#Variable sin inicializar
x : int

2. Colecciones

Para definir los tipos de las colecciones es necesario importar el módulo typing que viene incorporado en Python.

from typing import List, Set, Dict, Tuple

#Para las listas y los sets solo basta especificar
#el tipo entre corchetes
l : List[int] = [10, 20, 30]
s : Set[int] ={6, 9}

#Para los diccionarios debemos definir el tipo de datos para
#la clave y su valor
d : Dict[str, int] = {'item': 23}

#Para las tuplas podemos definir el tipo de dato
#para cada elemento en caso de que la tupla sea de tamaño fijo
t : Tuple[int, str, float, bool] = (1, 'Hola', 15.6, True)

#Si la tupla es de tamaño variable debemos definir el tipo
#seguido de puntos suspensivos
t : Tuple[float, ...] = (12.2, 15.3, 18.4, 16.2)

Si deseamos definir una lista de varios tipos de datos no podemos hacer el mismo procedimiento que se realiza con las tuplas. Para esto debemos hacer uso de la función Union del módulo typing.

from typing import List, Union

l: List[Union[int, str, float]] = [3, 5, 'hola', 'mundo', 15.6]

3. Funciones

En Python es posible hacer anotaciones de tipo en funciones sin necesidad de importar el módulo typing.

def numero_texto(num: int) -> str:
    return str(num)

def suma(n1: int, n2: int) -> int:
    return n1+n2

#Para valores por default debemos especificar
#el valor luego del tipo como una declaración normal de una variable
def multiplicacion(n1: int, n2:float=2.5) -> float:
    return n1*n2

Si por el contrario queremos hacer uso de colecciones debemos importar el módulo typing.

from typing import List

lista: List[int] = [1, 2, 3, 4, 5]

def imprimir_lista(x:List[int]) -> List[str]:
    print(str(x))

imprimir_lista(lista)

4. Clases

Para las clases podemos hacer uso de las mismas anotaciones referentes a variables y métodos dentro de una clase pero también existen algunas anotaciones extras que podemos realizar con las clases como definir anotaciones en métodos que no retornan ningún valor y definir como tipo las clases que ha creado el usuario.

class MiClase:

    attr1 : int = 100
    attr2 : str

        #Podemos usar la palabra None en caso de que el
        #método no retorne ningún valor
    def __init__(self) -> None:
        ...

    def metodo(self, n1: int, n2: int) -> int:
        return n1+n2

#Podemos incluir anotaciones referentes a la clase
#directamente en la instancia de la clase
instancia: MiClase = MiClase()

El uso de estas anotaciones facilita el mantenimiento del código y la legibilidad del mismo. Sin embargo, es importante recordar que estas anotaciones no impiden que el código de Python se ejecute, por ejemplo:

def multiplicacion(n1:int, n2: int) -> int:
    return n1*n2

print(multiplicacion(3, 'Hola'))

Se esperaría que el código no se compilara debido a que la función espera un número entero pero debido a la naturaleza del tipado dinámico de Python esto no sucede y obtendremos como resultado una cadena de texto. Sin duda es una desventaja pero es importante realizar estas anotaciones en proyectos de gran magnitud donde es fácil perder el control del código.

Existen muchas más anotaciones de tipo por explorar que se pueden revisar por completo en el siguiente enlace:

No hay comentarios:

Publicar un comentario