typing.get_type_hints() recupera anotações de funções, métodos, classes e módulos em uma forma mais útil do que acessar diretamente __annotations__. A função pode resolver referências futuras, substituir aliases especiais, combinar anotações herdadas e, quando solicitado, preservar metadados de Annotated.
Esse poder exige cuidado: resolver anotações pode depender de namespaces, importar nomes e avaliar expressões. Neste guia, você aprenderá a usar get_type_hints em decorators, validadores, geradores de schema, injeção de dependências e documentação, além de tratar forward references, Annotated, classes genéricas, erros e segurança.
__annotations__ básico
def somar(a: int, b: int) -> int:
return a + b
print(somar.__annotations__)O dicionário costuma conter as anotações declaradas. Porém, dependendo da versão e das opções do módulo, valores podem estar armazenados como strings ou objetos ainda não resolvidos.
Usando get_type_hints
from typing import get_type_hints
hints = get_type_hints(somar)
print(hints)A função retorna um mapping com parâmetros e a chave especial return. Tipos são resolvidos no contexto apropriado sempre que possível.
Referências futuras
class Usuario:
gerente: "Usuario | None"
print(Usuario.__annotations__)
print(get_type_hints(Usuario))O acesso direto pode mostrar uma string. get_type_hints tenta resolver o nome Usuario e construir a união real.
from __future__ import annotations
Quando o módulo usa anotações adiadas, muitas expressões ficam armazenadas de forma não avaliada. get_type_hints é uma forma centralizada de obter objetos de tipo resolvidos, mas precisa que os nomes referenciados estejam disponíveis.
Namespaces globais e locais
get_type_hints(objeto, globalns=globais, localns=locais)globalns e localns permitem controlar a resolução. Isso é útil para classes criadas dinamicamente, funções aninhadas e ferramentas que inspecionam código fora do módulo original. Forneça mappings corretos e mínimos.
Falhas de resolução
class Pedido:
cliente: "Cliente"Se Cliente não existe no namespace, get_type_hints pode lançar NameError. Ferramentas devem capturar erros, indicar qual anotação falhou e decidir se continuam com valores não resolvidos.
Annotated é removido por padrão
from typing import Annotated
def idade(valor: Annotated[int, "0 a 130"]) -> None:
...Por padrão, get_type_hints pode retornar apenas int, removendo metadados extras.
Preservando extras
hints = get_type_hints(idade, include_extras=True)Com include_extras=True, Annotated, Required, NotRequired e outros qualificadores relevantes podem ser preservados para ferramentas de schema e validação. Consulte Annotated no Python.
Inspecionando Annotated
from typing import get_args, get_origin
anotacao = hints["valor"]
print(get_origin(anotacao))
print(get_args(anotacao))get_origin() identifica o contêiner de typing e get_args() retorna tipo base e metadados. Não dependa de representações de string.
Funções decoradas
Decorators devem usar functools.wraps para preservar metadados e __wrapped__. get_type_hints pode seguir a função apropriada, mas wrappers mal construídos podem esconder a assinatura.
from functools import wraps
def log(func):
@wraps(func)
def wrapper(*args, **kwargs):
return func(*args, **kwargs)
return wrapperMétodos e classes
class Configuracao:
host: str
porta: int
print(get_type_hints(Configuracao))Para classes, a função considera anotações ao longo da MRO e combina bases, com membros da classe derivada tendo prioridade. Isso ajuda frameworks de modelos.
Herança
class Base:
id: int
class Derivada(Base):
nome: str
get_type_hints(Derivada)O resultado pode incluir id e nome. Se a subclasse redefine um campo, sua anotação substitui a base.
ClassVar e Final
Com include_extras=True, qualificadores podem permanecer disponíveis. Um framework deve decidir se trata ClassVar como campo de instância, configuração da classe ou item ignorado.
TypedDict
get_type_hints recupera tipos de valores, mas presença obrigatória e opcional também depende de __required_keys__ e __optional_keys__. Para schemas completos, combine as fontes.
Dataclasses
Em dataclasses, get_type_hints resolve tipos, enquanto dataclasses.fields() fornece defaults, factories, flags e metadados de campo. Um serializador normalmente precisa das duas APIs.
Aliases
Aliases modernos podem permanecer como entidades próprias ou ser avaliados conforme a API usada. Ferramentas devem decidir quando expandir TypeAliasType e quando preservar seu nome. Consulte TypeAliasType no Python.
Genéricos
from typing import Generic, TypeVar
T = TypeVar("T")
class Caixa(Generic[T]):
valor: Tget_type_hints na classe recupera T, mas não especializa automaticamente um objeto Caixa[int] em todos os contextos. Resolver parâmetros concretos exige acompanhar __orig_bases__, get_origin() e get_args(), com cuidado.
Objetos não suportados
Nem todo objeto possui anotações significativas. Bibliotecas devem verificar o tipo de entrada e produzir erros claros. Funções built-in e extensões C podem não expor metadados completos.
Avaliação e segurança
Anotações podem conter expressões. Avaliá-las pode executar código arbitrário em alguns cenários. Não processe anotações de fontes não confiáveis como se fossem dados inertes. Inspecione código confiável, limite namespaces e evite carregar módulos desconhecidos apenas para resolver tipos.
Não use como validador direto
get_type_hints informa o contrato declarado, mas não testa valores. Para validar uma lista, união, TypedDict ou Annotated, uma biblioteca precisa interpretar cada construção e produzir regras de runtime.
Cache
Resolver anotações repetidamente pode custar tempo. Frameworks podem armazenar resultados por função ou classe. Considere invalidação se o projeto modifica anotações dinamicamente, embora esse padrão seja melhor evitado.
Importações circulares
Forward references ajudam a escrever tipos sem importar tudo no topo, mas get_type_hints ainda precisa resolver os nomes quando executado. Use TYPE_CHECKING, módulos de modelos bem organizados e namespaces explícitos. Ferramentas podem adiar a resolução até que a aplicação esteja inicializada.
TYPE_CHECKING
from typing import TYPE_CHECKING
if TYPE_CHECKING:
from pacote import ClienteA importação existe apenas para o analisador. Em runtime, get_type_hints pode não encontrar Cliente. Se uma ferramenta precisa resolver a referência, disponibilize o nome de outra forma ou forneça globalns.
Exemplo de validador simples
from inspect import signature
from typing import get_type_hints
def validar_chamada(func, *args, **kwargs):
sig = signature(func)
ligados = sig.bind(*args, **kwargs)
hints = get_type_hints(func)
for nome, valor in ligados.arguments.items():
esperado = hints.get(nome)
if isinstance(esperado, type) and not isinstance(valor, esperado):
raise TypeError(f"{nome} deve ser {esperado.__name__}")Esse exemplo suporta apenas classes simples. Uniões, genéricos e Protocol exigem interpretação mais sofisticada. Não transforme uma demonstração em sistema de validação completo.
Gerador de documentação
Uma ferramenta pode combinar inspect.signature(), docstrings e get_type_hints para listar parâmetros, defaults, retornos e metadados. Preserve aliases públicos e Annotated quando eles melhorarem a documentação.
Erros comuns
- Usar apenas __annotations__: referências podem permanecer strings.
- Esquecer include_extras: metadados e qualificadores podem desaparecer.
- Ignorar NameError: referências futuras podem não ser resolvidas.
- Avaliar código não confiável: anotações não são necessariamente dados seguros.
- Tratar hints como validação: ainda é preciso verificar valores.
- Resolver em cada chamada: cache pode ser necessário.
Exemplo completo: registro de handlers
from typing import Annotated, 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("handler deve retornar None")
handlers[evento] = func
return func
@handler
def processar(evento: Evento, contexto: Contexto) -> None:
...O decorator usa as anotações para registrar funções. Uma implementação real também verificaria nomes, quantidade de parâmetros, subclasses específicas e mensagens de erro.
Quando evitar introspecção
Se a interface pode ser declarada explicitamente, um registro com argumentos costuma ser mais simples e previsível. Use get_type_hints quando as próprias anotações são parte intencional da API, como em frameworks, serializadores, documentação e injeção de dependências.
Conclusão
get_type_hints() é a principal ferramenta para obter anotações resolvidas em runtime. Ele trata referências futuras, herança e extras de typing melhor que o acesso direto a __annotations__.
A documentação oficial de get_type_hints no módulo typing explica os parâmetros. Use namespaces controlados, preserve extras quando necessário, trate falhas de resolução e nunca avalie anotações não confiáveis sem considerar o risco de execução de código.







