HerramientasMypy en Python

Mypy en Python

Python es famoso por ser un lenguaje de tipado dinámico. Esto significa que puedes redefinir variables al vuelo y que no necesitas declarar si una variable es un número, un texto o una lista. Aunque esta flexibilidad permite escribir prototipos a velocidad récord, en proyectos del mundo real puede convertirse en una pesadilla: un simple error al pasar una cadena de texto a una función que espera un entero provocará que tu servidor reviente en producción. Para solucionar este problema de raíz y dotar a tus proyectos de una solidez profesional, la herramienta estándar de la industria es mypy python.

En esta guía técnica vas a aprender qué es el tipado estático, cómo implementar anotaciones de tipo (Type Hints) y cómo usar Mypy como un compilador de tipos para detectar fallos catastróficos antes de que tu código llegue a ejecutarse.

Para abrir el apetito del código robusto, echa un vistazo al siguiente bloque «spoiler» de código que muestra la diferencia entre un código estándar peligroso y un código profesional verificado mediante mypy python:

# Código común con un bug silencioso que pasará a producción
def calcular_impuesto(precio, tasa):
    return precio * tasa

# Esto provocará un fallo en ejecución: TypeError
calcular_impuesto(100.0, "0.21")

# Código profesional anotado y listo para Mypy
def calcular_impuesto_seguro(precio: float, tasa: float) -> float:
    return precio * tasa

# Mypy te avisará inmediatamente antes de ejecutar:
# "Argument 2 to 'calcular_impuesto_seguro' has incompatible type 'str'; expected 'float'"
calcular_impuesto_seguro(100.0, "0.21")

1. ¿Qué es Mypy y por qué Python no impone tipos en ejecución?

Es fundamental comprender una regla de oro de Python: el intérprete ignora por completo las anotaciones de tipo en tiempo de ejecución. Si escribes una función declarando que un parámetro es una cadena de texto (def saludar(nombre: str)), Python no lanzará ningún error si en producción le pasas un número entero o un diccionario. Las anotaciones son meras etiquetas informativas.

Aquí es donde entra en juego mypy python. Mypy es un analizador estático de código. No ejecuta tu código, sino que lo «lee» y comprueba que todas las llamadas a funciones, retornos y asignaciones de variables respeten las firmas de tipos que has declarado en las anotaciones.

Actúa de forma idéntica al compilador de lenguajes como Java, TypeScript o C#, ofreciéndote una red de seguridad inestimable al refactorizar grandes bases de código.


2. Instalación y Uso Básico de Mypy

Mypy no viene instalado por defecto en Python, pero es una librería estándar en cualquier flujo de integración continua. Puedes instalarlo de forma sumamente sencilla en tu entorno virtual utilizando Pip:

pip install mypy

Una vez instalado, puedes verificar cualquier archivo ejecutable de Python corriendo el comando desde tu terminal favorita:

mypy tu_script.py

Si tu código está libre de errores de tipado, Mypy te devolverá un agradable mensaje: Success: no issues found in 1 source file. Si hay discrepancias, te indicará de forma milimétrica el archivo, la línea y la descripción exacta del error detected.


3. Dominando los Type Hints Fundamentales

Para sacarle el máximo partido a mypy python, debes aprender a anotar tus variables y funciones de forma correcta. A continuación, repasamos la sintaxis estándar recomendada por la comunidad:

A. Anotación de Variables Simples

Para declarar tipos en variables individuales, basta con añadir dos puntos (:) y el nombre del tipo antes del signo de asignación:

nombre: str = "Ana"
edad: int = 30
precio: float = 19.99
activo: bool = True

B. Estructuras de Datos y Colecciones

Si estás utilizando una versión moderna de Python (3.9 o superior), puedes anotar colecciones directamente con los tipos nativos en minúsculas. Si usas versiones anteriores, tendrás que importar los equivalentes en mayúsculas desde el módulo typing:

# Sintaxis moderna (Python 3.9+)
lista_numeros: list[int] = [1, 2, 3]
diccionario_precios: dict[str, float] = {"manzana": 1.5, "platano": 0.8}
tupla_coordenadas: tuple[int, int] = (10, 20)

# Sintaxis compatible con versiones anteriores (Python < 3.9)
from typing import List, Dict, Tuple
lista_numeros_antigua: List[int] = [1, 2, 3]
diccionario_precios_antiguo: Dict[str, float] = {"manzana": 1.5}

C. Firmas completas en Funciones

La anotación en funciones es el lugar más crítico, ya que documenta el comportamiento de tu lógica. Anota siempre cada parámetro de entrada y define el tipo de retorno usando el símbolo ->:

def concatenar_nombres(prefijo: str, nombres: list[str]) -> list[str]:
    resultados: list[str] = []
    for n in nombres:
        resultados.append(f"{prefijo} {n}")
    return resultados

4. El Salvador del Tipado: Optional, Union y la Sintaxis Moderna

Uno de los errores más comunes de Mypy es cuando intentamos procesar una variable que puede tomar un valor nulo (None). Por ejemplo, si buscas un registro en una base de datos y la función devuelve el objeto o None si no lo encuentra.

Si intentas usar un método de ese objeto directamente, Mypy bloqueará el análisis avisando de que el tipo es opcional y puede no tener dicho método. Para solucionar este dolor de cabeza, usamos Optional o el operador de unión moderno |:

from typing import Optional

# Sintaxis clásica con modulo typing
def buscar_usuario_clasico(id_usuario: int) -> Optional[str]:
    if id_usuario == 1:
        return "Ana Lopez"
    return None

# Sintaxis moderna e intuitiva (Python 3.10+)
def buscar_usuario_moderno(id_usuario: int) -> str | None:
    if id_usuario == 1:
        return "Ana Lopez"
    return None

El secreto del Type Narrowing (Estrechamiento de Tipos): Una vez que devuelves un tipo opcional, Mypy te obligará a escribir un bloque de validación para asegurar de que el valor no es nulo antes de operar con él. Esto evita de raíz los temidos fallos del estilo AttributeError: 'NoneType' object has no attribute... en producción:

resultado = buscar_usuario_moderno(2)

# NO RECOMENDADO: Mypy protestará porque resultado puede ser None
print(resultado.upper())

# RECOMENDADO: Mypy analiza tu condicional y valida el tipado de forma segura
if resultado is not None:
    print(resultado.upper()) # Aquí Mypy sabe al 100% que es un str
else:
    print("Usuario no encontrado.")

5. Configuración Profesional de Mypy con pyproject.toml

Correr Mypy manualmente está bien para aprender, pero en equipos profesionales automatizamos su comportamiento. Para ello, la mejor práctica estándar es definir la configuración dentro del archivo pyproject.toml de la raíz de tu proyecto. Aquí tienes una plantilla de producción altamente recomendada:

[tool.mypy]
python_version = "3.10"
disallow_untyped_defs = true
ignore_missing_imports = true
warn_unused_configs = true
warn_return_any = true

¿Qué significan estas reglas críticas?

  • disallow_untyped_defs = true: Obliga a que absolutamente todas las funciones tengan Type Hints definidos. Si alguien intenta colar una función sin anotar, Mypy rechazará el código.
  • ignore_missing_imports = true: Evita que Mypy tire errores si utilizas librerías externas de terceros (como Django o Flask tradicionales) que no cuentan con definiciones de tipos nativos.
  • warn_return_any = true: Te alerta si una función que tiene declarada una salida específica termina devolviendo un tipo Any de forma accidental.

6. Tabla de Comparación de Tipos Frecuentes

En esta tabla responsiva resumimos los principales tipos de anotación que utilizarás en tus proyectos analizados con mypy python:

Tipo de DatoSintaxis de AnotaciónCaso de Uso Recomendado
Entero / Flotanteint / floatVariables de conteo numérico, precios, coordenadas decimales.
Texto / Buleanostr / boolCadenas de texto, identificadores alfanuméricos, banderas lógicas.
Lista de elementoslist[tipo]Colecciones homogéneas de datos ordenados e indexables.
Valores Opcionalestipo | NoneDatos recuperados que pueden ser nulos o no existir en disco.
Cualquier TipoAnyÚltimo recurso cuando la estructura es tan dinámica que no se puede tipar.

Conclusión y Buenas Prácticas

Integrar el tipado estático mediante mypy python es el paso definitivo para transformar tu código de scripts amateur a software robusto de nivel enterprise. Para mantener un flujo impecable, recuerda aplicar siempre estas tres buenas prácticas del sector: evita el abuso abusivo de Any (ya que deshabilita las protecciones de Mypy), utiliza la sintaxis moderna con el operador unión | para mantener firmas limpias y configura reglas estrictas en tu archivo pyproject.toml para integrarlo de forma automática en tus pipelines de Git. Te animamos a profundizar consultando la documentación oficial de Mypy y a adoptar hoy mismo este hábito profesional. ¡Notarás de inmediato cómo tu editor de código te asiste mejor y cómo disminuyen a cero los bugs tontos en tus sistemas!