get_type_hints en Python: lee anotaciones

Publicado el: 29/08/2026
Tempo de leitura: 5 minutos
A person typing on a laptop with a Python programming book visible, capturing technology and learning.

typing.get_type_hints() recupera anotaciones de funciones, métodos, clases y módulos en una forma más útil que leer directamente __annotations__. Puede resolver referencias futuras, combinar anotaciones heredadas y conservar metadatos de Annotated cuando se solicita.

Ese poder requiere cuidado porque la resolución depende de namespaces y puede evaluar expresiones. Esta guía cubre decoradores, validadores, schemas, inyección de dependencias, documentación, forward references, genéricos, errores, caché, imports circulares y seguridad.

__annotations__ básico

def sumar(a: int, b: int) -> int:
    return a + b

print(sumar.__annotations__)

El diccionario contiene las anotaciones declaradas, pero algunos valores pueden ser strings u objetos no resueltos según la versión y la configuración del módulo.

Usar get_type_hints

from typing import get_type_hints

hints = get_type_hints(sumar)
print(hints)

El resultado mapea nombres de parámetros y la clave especial return a objetos de tipo resueltos cuando es posible.

Referencias futuras

class Usuario:
    gerente: "Usuario | None"

print(Usuario.__annotations__)
print(get_type_hints(Usuario))

El acceso directo puede mostrar una string. get_type_hints intenta resolver Usuario y construir la unión real.

Anotaciones diferidas

Cuando el módulo usa evaluación diferida, las expresiones permanecen sin evaluar. get_type_hints es una forma centralizada de resolverlas siempre que los nombres estén disponibles.

Namespaces globales y locales

get_type_hints(objeto, globalns=globales, localns=locales)

Los namespaces explícitos ayudan con clases dinámicas, funciones anidadas y herramientas que inspeccionan objetos fuera de su módulo original. Proporciona mappings correctos y mínimos.

Fallos de resolución

class Pedido:
    cliente: "Cliente"

Si Cliente no está disponible, get_type_hints puede lanzar NameError. Las herramientas deben capturar el fallo, identificar la anotación y decidir si aceptan valores no resueltos.

Annotated se elimina por defecto

from typing import Annotated

def edad(valor: Annotated[int, "0 a 130"]) -> None:
    ...

Sin opciones extra, el resultado puede contener solo int.

Conservar extras

hints = get_type_hints(edad, include_extras=True)

include_extras=True conserva Annotated, Required, NotRequired y calificadores relacionados. Consulta Annotated en Python.

Inspeccionar Annotated

from typing import get_args, get_origin

anotacion = hints["valor"]
print(get_origin(anotacion))
print(get_args(anotacion))

Usa las APIs de typing en lugar de analizar representaciones de texto. get_args() devuelve el tipo base y los metadatos.

Funciones decoradas

Los decoradores deben usar functools.wraps para conservar metadatos y __wrapped__. Un wrapper mal implementado puede ocultar las anotaciones.

from functools import wraps

def log(func):
    @wraps(func)
    def wrapper(*args, **kwargs):
        return func(*args, **kwargs)
    return wrapper

Clases y métodos

class Configuracion:
    host: str
    puerto: int

print(get_type_hints(Configuracion))

Para clases, la función combina anotaciones a lo largo del MRO. Las definiciones derivadas tienen prioridad.

Herencia

class Base:
    id: int

class Derivada(Base):
    nombre: str

get_type_hints(Derivada)

El resultado puede incluir id y nombre. Una anotación derivada sustituye a la base con el mismo nombre.

ClassVar y Final

Con extras preservados, un framework puede distinguir campos de instancia, variables de clase y declaraciones finales. Cada herramienta decide cómo documentarlos o ignorarlos.

TypedDict

get_type_hints recupera tipos de valores, mientras que la presencia de claves depende también de __required_keys__ y __optional_keys__. Un generador de schema debe combinar ambas fuentes.

Dataclasses

En dataclasses, get_type_hints resuelve tipos y dataclasses.fields() aporta defaults, factories, flags y metadatos. Los serializadores suelen necesitar las dos APIs.

Alias de tipo

Los alias modernos pueden mantenerse como entidades nombradas o evaluarse según la ruta de inspección. Decide cuándo expandir TypeAliasType y cuándo conservar su nombre. Consulta TypeAliasType en Python.

Genéricos

from typing import Generic, TypeVar

T = TypeVar("T")

class Caja(Generic[T]):
    valor: T

get_type_hints recupera T, pero no sustituye automáticamente int en todos los contextos de Caja[int]. La especialización concreta requiere orígenes, argumentos y bases genéricas.

Objetos no soportados

No todo objeto expone anotaciones útiles. Built-ins y extensiones C pueden carecer de metadatos completos. Valida la entrada y produce mensajes claros.

Evaluación y seguridad

Las anotaciones pueden contener expresiones. Resolverlas puede ejecutar código en ciertos escenarios. No trates anotaciones de fuentes no confiables como datos inertes. Limita namespaces y evita importar módulos desconocidos solo para resolver hints.

No es un validador directo

get_type_hints describe el contrato declarado, pero no prueba valores. Un validador debe interpretar uniones, colecciones, TypedDict, Protocol, Annotated, recursión y metadatos personalizados.

Caché

Resolver repetidamente puede ser costoso. Los frameworks suelen guardar resultados por función o clase. Modificar anotaciones dinámicamente complica la invalidación y es mejor evitarlo.

Imports circulares

Las referencias futuras reducen imports superiores, pero get_type_hints necesita nombres durante la resolución. Organiza módulos, usa namespaces explícitos y retrasa la evaluación hasta la inicialización cuando sea necesario.

Imports con TYPE_CHECKING

from typing import TYPE_CHECKING

if TYPE_CHECKING:
    from paquete import Cliente

El import existe solo para análisis estático. En runtime, get_type_hints puede no encontrar Cliente. Proporciona el nombre mediante un import real o globalns.

Validador de llamada simple

from inspect import signature
from typing import get_type_hints


def validar_llamada(func, *args, **kwargs):
    sig = signature(func)
    ligados = sig.bind(*args, **kwargs)
    hints = get_type_hints(func)
    for nombre, valor in ligados.arguments.items():
        esperado = hints.get(nombre)
        if isinstance(esperado, type) and not isinstance(valor, esperado):
            raise TypeError(f"{nombre} debe ser {esperado.__name__}")

La demostración soporta clases simples. Uniones, genéricos, Protocol y estructuras anidadas exigen un motor completo.

Generación de documentación

Una herramienta puede combinar inspect.signature(), docstrings, defaults y get_type_hints. Conserva alias públicos y Annotated cuando mejoren el contrato generado.

Errores comunes

  • Leer solo __annotations__: referencias pueden seguir siendo strings.
  • Olvidar include_extras: metadatos y calificadores desaparecen.
  • Ignorar NameError: algunos nombres no se pueden resolver.
  • Evaluar código no confiable: las anotaciones no siempre son datos seguros.
  • Tratar hints como validación: todavía hay que comprobar valores.
  • Resolver en cada llamada: puede ser necesario cachear.

Ejemplo completo: registro de handlers

from typing import get_type_hints

class Evento: ...
class Contexto: ...

handlers: dict[type[Evento], object] = {}

def handler(func):
    hints = get_type_hints(func, include_extras=True)
    evento = hints.get("evento")
    retorno = hints.get("return")
    if not isinstance(evento, type) or not issubclass(evento, Evento):
        raise TypeError("parámetro evento inválido")
    if retorno is not None and retorno is not type(None):
        raise TypeError("el handler debe devolver None")
    handlers[evento] = func
    return func

@handler
def procesar(evento: Evento, contexto: Contexto) -> None:
    ...

El decorador usa las anotaciones como API intencional. Una implementación real también comprobaría nombres, cantidad de parámetros y mensajes de error.

Cuándo evitar introspección

Si la interfaz puede registrarse explícitamente, pasar argumentos suele ser más simple y predecible. Usa get_type_hints cuando las anotaciones sean parte intencional de un framework, como serialización, inyección, validación o documentación.

Conclusión

get_type_hints() es la herramienta principal para recuperar anotaciones resueltas en runtime. Maneja referencias futuras, herencia y extras mejor que __annotations__.

La documentación oficial de get_type_hints en Python describe sus parámetros. Usa namespaces controlados, conserva extras cuando sea necesario, maneja fallos, cachea responsablemente y nunca evalúes anotaciones no confiables sin considerar el riesgo de ejecución.

Compartilhe:

Facebook
WhatsApp
Twitter
LinkedIn

Contenido del artículo

    Artículos relacionados

    Estructura de código y XML para canonicalización con Python
    Python Avanzado
    Foto de perfil de Leandro Hirt da Academify

    ElementTree canonicalize: normaliza XML en Python

    Aprende ElementTree canonicalize en Python para comparar XML, generar hashes estables y controlar namespaces, espacios y comentarios.

    Ler mais

    Tempo de leitura: 5 minutos
    22/10/2026
    Código Python en una pantalla
    Python Avanzado
    Foto de perfil de Leandro Hirt da Academify

    T-strings y templatelib: interpolación estructurada

    Aprende t-strings y string.templatelib en Python para interpolación estructurada, renderizado seguro, logs y procesamiento personalizado.

    Ler mais

    Tempo de leitura: 6 minutos
    22/10/2026
    Base SQLite y código Python para exportación selectiva con iterdump
    Python Avanzado
    Foto de perfil de Leandro Hirt da Academify

    SQLite iterdump: crea dumps selectivos en Python

    Aprende sqlite3.Connection.iterdump con filtro para crear dumps SQLite selectivos, validar dependencias y restaurar con seguridad.

    Ler mais

    Tempo de leitura: 4 minutos
    21/10/2026
    Código y archivos que representan compresión de datos con Python
    Python Avanzado
    Foto de perfil de Leandro Hirt da Academify

    compression.zstd: Zstandard rápido en Python

    Aprende compression.zstd en Python para comprimir archivos y datos con velocidad, streaming, integridad y seguridad.

    Ler mais

    Tempo de leitura: 7 minutos
    21/10/2026
    Archivo de configuración y estructura de código para ConfigParser en Python
    Python Avanzado
    Foto de perfil de Leandro Hirt da Academify

    ConfigParser: lee INI sin sección en Python

    Aprende ConfigParser sin sección en Python con validación, tipos, compatibilidad, capas de configuración y escritura segura.

    Ler mais

    Tempo de leitura: 5 minutos
    20/10/2026
    Datos binarios y memoria de ordenador representando memoryview en Python
    Python Avanzado
    Foto de perfil de Leandro Hirt da Academify

    memoryview count e index: busca sin copiar

    Aprende memoryview count e index en Python para buscar valores en buffers sin copias y validar datos binarios con eficiencia.

    Ler mais

    Tempo de leitura: 5 minutos
    20/10/2026