Skip to content

📙 Clase 27 — Type hints

Fase 5 · Python intermedio / "pro" ⬅️ Volver al índice de clases

🎯 Qué aprendí

  • Anotar tipos: def f(x: int) -> str — documentación que el editor entiende.
  • Tipos compuestos (list[dict], str | None) y anotar clases propias.
  • Los hints no validan en runtime: son para el editor, el linter y los humanos.

📖 PARTE TEÓRICA

🏷️ 1. La sintaxis

python
def saludar(nombre: str, veces: int = 1) -> str:
    #         │                │              └── tipo de lo que DEVUELVE
    #         │                └── con default: el hint va antes del =
    #         └── tipo del parámetro
    return ", ".join([f"Hola {nombre}"] * veces)

print(saludar("Ana", 2))    # Hola Ana, Hola Ana

Variables también (útil cuando el editor no puede deducir):

python
tareas: list[dict] = []
total: float = 0.0

🧩 2. Tipos compuestos (Python moderno)

HintSignifica
list[str]lista de strings
dict[str, int]dict con claves str y valores int
list[dict]tu clásica lista de diccionarios
tuple[bool, str]el (ok, mensaje) de tus validaciones
str | Noneun string o None (el "no encontrado")
Contacto¡tus propias clases son tipos!
python
def buscar(tareas: list[dict], texto: str) -> list[dict]:
    return [t for t in tareas if texto in t["texto"]]

def hallar(nombres: list[str], letra: str) -> str | None:
    for n in nombres:
        if n.startswith(letra):
            return n
    return None                # el hint AVISA que puede no encontrar

📌 str | None (en vez del viejo Optional[str]) funciona desde Python 3.10; tu 3.14 lo soporta de sobra. Igual list[str] en vez del viejo List[str] de typing.

🚨 3. La verdad incómoda: NO validan

python
print(saludar(123, 1))     # "Hola 123"  ← ¡pasó un int y NO explotó!

Los hints son anotaciones, no cadenas: Python los guarda (f.__annotations__) y sigue. ¿Quién los aprovecha?

HerramientaQué hace con los hints
Tu editor (VS Code/Pylance)autocompletado preciso + subrayar errores de tipo al escribir
mypy (pip install mypy)revisa todo el proyecto: mypy app.py
Humanos (tu yo del futuro)la firma documenta qué entra y qué sale

🧪 Tip de entrevista: "¿Python valida los type hints en ejecución?" → No. Son metadatos para herramientas de análisis estático (mypy, el editor) y documentación. La validación en runtime sigue siendo tu responsabilidad (o de librerías como pydantic).


🖥️ EN TU APP DE ESCRITORIO

Donde más brillan: la frontera entre tus módulos (uilogicadatos, Clase 11). Las firmas se vuelven contratos:

python
# logica.py — se LEE qué entra y qué sale, sin abrir la función
def validar_contacto(nombre: str, tel: str) -> tuple[bool, str]:
    ...

# datos.py
def cargar_tareas(ruta: Path) -> list[Tarea]:      # tus clases como tipos
    ...

def buscar_contacto(con, id: int) -> Contacto | None:   # "puede no existir" EXPLÍCITO
    ...

Y el beneficio diario: al escribir tarea. el editor sabe que es una Tarea y te autocompleta .texto, .hecha, .alternar() — la mitad de los typos mueren antes de correr.

💡 No hay que anotar TODO. Prioriza: ① firmas públicas entre módulos, ② funciones cuyo retorno no es obvio (-> str | None), ③ estructuras ambiguas (list[dict]). Dentro de una función corta, el editor deduce solo.


🗄️ CON BASE DE DATOS (caso de uso)

Las funciones de BD son las más ambiguas sin hints — ¿devuelve tuplas?, ¿dicts?, ¿objetos? El hint responde de una vez:

python
def obtener_contactos(con) -> list[tuple[str, str]]:    # filas crudas
    return con.execute("SELECT nombre, tel FROM contactos").fetchall()

def obtener_contactos_obj(con) -> list[Contacto]:       # ya convertidas
    return [Contacto(n, t) for n, t in obtener_contactos(con)]

🏋️ EJERCICIOS CON SOLUCIÓN

Ejercicio 1 — Anota

Agrega hints completos a: def repetir(texto, veces): return texto * veces

Ver solución
python
def repetir(texto: str, veces: int) -> str:
    return texto * veces

Ejercicio 2 — El "puede fallar"

Anota def a_numero(texto) que devuelve int(texto) o None si no se puede.

Ver solución
python
def a_numero(texto: str) -> int | None:
    try:
        return int(texto)
    except ValueError:
        return None

Ejercicio 3 — Lee la firma

Sin ver el cuerpo, ¿qué te dice esta firma? def agrupar(gastos: list[dict]) -> dict[str, float]:

Ver solución
python
# Recibe una lista de diccionarios (gastos) y devuelve un dict que mapea
# strings a floats — casi seguro {categoria: total}. Eso es documentación
# ejecutable: entendiste la función sin leerla.

❓ Preguntas y respuestas (autoevaluación)

1. ¿Qué pasa en runtime si pasas un tipo distinto al anotado?

Nada: los hints no se validan al ejecutar. Los revisan el editor y mypy.

2. ¿Cómo anotas "devuelve un string o None"?

-> str | None (Python ≥ 3.10).

3. ¿Cómo anotas tu clásica lista de diccionarios?

list[dict] (o más preciso: list[dict[str, str]]).

4. ¿Dónde conviene más invertir en hints?

En las firmas públicas entre módulos (logica, datos) y en retornos no obvios.


📎 Apuntes relacionados

  • Los módulos cuyas fronteras anotas → Clase 11
  • El (ok, msg) que ahora es tuple[bool, str]Clase 08

➡️ Siguiente

Clase 28 · Context managers — crear tus propios with.