Apariencia
📙 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 AnaVariables también (útil cuando el editor no puede deducir):
python
tareas: list[dict] = []
total: float = 0.0🧩 2. Tipos compuestos (Python moderno)
| Hint | Significa |
|---|---|
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 | None | un 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 viejoOptional[str]) funciona desde Python 3.10; tu 3.14 lo soporta de sobra. Iguallist[str]en vez del viejoList[str]detyping.
🚨 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?
| Herramienta | Qué 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 (ui ↔ logica ↔ datos, 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 * vecesEjercicio 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 NoneEjercicio 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
➡️ Siguiente
Clase 28 · Context managers — crear tus propios with.