---
title: "Python 3.14: annotationlib e Anotações"
url: "https://python.dev.br/blog/python-3-14-annotationlib-anotacoes/"
markdown_url: "https://python.dev.br/blog/python-3-14-annotationlib-anotacoes.MD"
description: "Entenda annotationlib no Python 3.14, como funcionam anotações lazy e o impacto prático em tipagem, introspecção e frameworks."
date: "2026-04-10"
author: "Equipe python.dev.br"
---

# Python 3.14: annotationlib e Anotações

Entenda annotationlib no Python 3.14, como funcionam anotações lazy e o impacto prático em tipagem, introspecção e frameworks.


Quem trabalha com tipagem em Python já esbarrou em alguns problemas clássicos: referências futuras que quebram em tempo de execução, necessidade de usar strings nas anotações, diferenças entre o que o type checker enxerga e o que o runtime consegue interpretar, além de incompatibilidades em frameworks que inspecionam tipos.

No Python 3.14, esse cenário muda bastante com a chegada de uma nova base para introspecção de anotações. As **PEPs 649 e 749** consolidam um modelo de **avaliação tardia** das anotações, e a biblioteca padrão passa a incluir o módulo **`annotationlib`** para lidar com esse comportamento de forma explícita.

Em termos práticos, o objetivo é simples: tornar as anotações mais úteis tanto para **type checkers** quanto para **frameworks de runtime**, sem depender tanto de workarounds. Para quem usa `dataclasses`, Pydantic, ORMs, FastAPI, decorators ou introspecção dinâmica, essa mudança merece atenção.

Neste artigo, vamos entender o que é o `annotationlib`, por que ele importa e como o novo modelo de anotações afeta o código real.

## O problema das anotações em Python

Desde que type hints ganharam força, Python passou a usar anotações em muitos contextos:

- documentação de funções;
- validação de dados;
- serialização;
- geração automática de schemas;
- injeção de dependência;
- tooling de IDE e lint.

O problema é que, historicamente, havia uma tensão entre dois mundos:

1. **o mundo da tipagem estática**, que quer expressividade;
2. **o mundo do runtime**, que quer objetos reais e introspecção confiável.

Considere este exemplo:

```python
class Usuario:
    pass


def buscar_usuario(user_id: int) -> Usuario:
    return Usuario()
```

Isso parece simples, mas em cenários mais complexos surgem referências futuras, imports circulares e momentos em que a anotação ainda não pode ser resolvida. Ao longo dos anos, a comunidade recorreu a strings, `from __future__ import annotations` e chamadas como `typing.get_type_hints()` para contornar essas situações.

O Python 3.14 tenta organizar melhor essa história.

## O que muda no Python 3.14?

A documentação do Python 3.14 afirma que as anotações de funções, classes e módulos **não são mais avaliadas eagerly**. Em vez disso, elas passam a ser associadas a uma estrutura interna que pode gerar as anotações sob demanda.

Na prática, isso significa:

- menos avaliação prematura de tipos;
- menos atrito com forward references;
- mais consistência para introspecção;
- uma API mais clara para ferramentas que precisam acessar anotações.

Esse novo modelo é a base das PEPs 649 e 749. Em vez de tratar anotações apenas como strings ou apenas como valores já resolvidos, o runtime passa a oferecer formatos diferentes conforme a necessidade.

## Conhecendo o annotationlib

O `annotationlib` é o novo módulo da biblioteca padrão voltado para introspecção de anotações. Ele centraliza operações que interessam tanto a bibliotecas quanto a frameworks.

Um dos pontos principais é a possibilidade de pedir anotações em formatos diferentes. A documentação destaca três formatos úteis:

- `VALUE`
- `FORWARDREF`
- `STRING`

Vamos ver isso com um exemplo prático.

```python
from annotationlib import get_annotations, Format


def processar(pedido: Pedido):
    return pedido
```

Se `Pedido` ainda não estiver definido no contexto de runtime, pedir as anotações como valores concretos pode falhar. Mas com `annotationlib`, você escolhe o formato mais apropriado.

### 1. Format.VALUE

Esse formato tenta retornar o valor real da anotação:

```python
from annotationlib import get_annotations, Format


def criar_relatorio(dados: list[str]) -> dict[str, int]:
    return {item: len(item) for item in dados}

anotacoes = get_annotations(criar_relatorio, format=Format.VALUE)
print(anotacoes)
```

Saída esperada:

```python
{
    'dados': list[str],
    'return': dict[str, int]
}
```

Esse modo é útil quando você quer trabalhar com os tipos reais no runtime, como fazem validadores, frameworks web e geradores de schema.

### 2. Format.FORWARDREF

Quando existe uma referência ainda não resolvida, você pode pedir um objeto representando essa referência, em vez de quebrar o código:

```python
from annotationlib import get_annotations, Format


def carregar_usuario(usuario: UsuarioInexistente):
    return usuario

anotacoes = get_annotations(carregar_usuario, format=Format.FORWARDREF)
print(anotacoes)
```

Nesse caso, o runtime pode devolver algo equivalente a um `ForwardRef`, preservando a informação sem exigir resolução imediata.

Isso é especialmente relevante para frameworks que montam metadados, mas não querem estourar erro só porque uma classe será importada depois.

### 3. Format.STRING

Há momentos em que você quer apenas a representação textual da anotação, seja para documentação, serialização ou análise estática complementar:

```python
from annotationlib import get_annotations, Format


def enviar(payload: dict[str, str]) -> list[int]:
    return [200]

anotacoes = get_annotations(enviar, format=Format.STRING)
print(anotacoes)
```

Saída esperada:

```python
{
    'payload': 'dict[str, str]',
    'return': 'list[int]'
}
```

Esse modelo oferece uma flexibilidade que faltava no ecossistema.

## Exemplo real: evitando dor com referências futuras

Um caso muito comum em projetos grandes é a relação entre classes que se referenciam mutuamente. Em versões anteriores, isso frequentemente exigia strings ou imports locais.

```python
from annotationlib import get_annotations, Format


class Pedido:
    def __init__(self, cliente: "Cliente"):
        self.cliente = cliente


class Cliente:
    def __init__(self, pedidos: list[Pedido] | None = None):
        self.pedidos = pedidos or []


anotacoes = get_annotations(Pedido.__init__, format=Format.STRING)
print(anotacoes)
```

Com o novo modelo, a introspecção se torna mais previsível. Isso tende a reduzir parte da fricção entre design orientado a tipos e execução real do programa.

Se você quer reforçar sua base antes de avançar nesse tema, vale revisar também nossos conteúdos sobre [type hints em Python](/glossario/type-hints/), [tipagem estática com mypy](/blog/tipagem-estatica-python-mypy/) e [protocols e tipagem estrutural](/blog/python-protocols-tipagem-estrutural/).

## Impacto prático em frameworks e bibliotecas

Essa mudança não interessa apenas a quem usa type checkers. Ela também afeta bibliotecas que dependem de anotações no runtime.

### FastAPI e APIs tipadas

Frameworks como FastAPI usam anotações para:

- validar parâmetros;
- gerar OpenAPI;
- converter tipos automaticamente;
- documentar endpoints.

Se o acesso às anotações fica mais consistente, a tendência é reduzir hacks internos e melhorar a confiabilidade da introspecção. Isso é relevante para qualquer equipe que constrói APIs modernas com Python. Veja também nosso guia sobre [APIs REST com FastAPI](/blog/apis-rest-com-fastapi/).

### Dataclasses, Pydantic e validação

Ferramentas como `dataclasses` e Pydantic também se beneficiam porque operam em cima de campos anotados. Com resolução mais clara e APIs dedicadas para buscar anotações, bibliotecas desse tipo podem lidar melhor com forward references e casos avançados.

```python
from dataclasses import dataclass
from annotationlib import get_annotations, Format


@dataclass
class Produto:
    nome: str
    preco: float
    estoque: int


print(get_annotations(Produto, format=Format.VALUE))
```

Esse tipo de introspecção é útil para builders de formulário, geradores de documentação e validadores internos.

Se esse tema faz parte do seu dia a dia, vale reler também nosso artigo sobre [Pydantic e validação de dados](/blog/pydantic-validacao-dados-python/).

### Decorators e metaprogramação

Decorators que analisam assinaturas e tipos podem ficar mais previsíveis com o novo modelo. Em vez de assumir que `__annotations__` já está resolvido ou contém apenas strings, a biblioteca passa a ter uma camada mais explícita para lidar com formatos diferentes.

Um exemplo simples:

```python
from annotationlib import get_annotations, Format
from functools import wraps


def auditar_tipos(func):
    @wraps(func)
    def wrapper(*args, **kwargs):
        anotacoes = get_annotations(func, format=Format.STRING)
        print("Anotações:", anotacoes)
        return func(*args, **kwargs)
    return wrapper


@auditar_tipos
def salvar_usuario(nome: str, ativo: bool) -> None:
    print("Usuário salvo")


salvar_usuario("Ana", True)
```

Esse padrão pode aparecer bastante em tooling interno, bibliotecas de RPC, ORMs e camadas de integração.

## Isso elimina `typing.get_type_hints()`?

Não necessariamente. Mas o Python 3.14 sinaliza uma reorganização importante. A própria documentação indica que `inspect.get_annotations()` passa a delegar parte dessa responsabilidade ao `annotationlib`, que se torna a casa mais explícita para esse tipo de operação.

Na prática, é provável que:

- bibliotecas novas adotem `annotationlib` gradualmente;
- bibliotecas antigas mantenham compatibilidade por um tempo;
- times que fazem tooling ou infraestrutura passem a preferir a API nova.

Ou seja: não é uma ruptura total, mas é uma direção clara.

## Vale a pena se preparar agora?

Sim, principalmente se você atua em uma destas áreas:

- APIs com tipagem forte;
- frameworks internos;
- validação e serialização;
- geração automática de código ou schema;
- ferramentas de análise estática e introspecção;
- bibliotecas que inspecionam funções, classes ou módulos.

Mesmo que seu código atual continue funcionando, entender `annotationlib` ajuda a evitar surpresas quando a base do projeto migrar para Python 3.14.

## Conclusão

O `annotationlib` é mais do que um módulo novo: ele representa uma tentativa séria de tornar o ecossistema de anotações do Python mais coerente. Com as PEPs 649 e 749, o Python 3.14 aproxima melhor o universo da tipagem estática e o do runtime, oferecendo formatos explícitos para acessar anotações conforme a necessidade.

Para quem escreve aplicações simples, talvez essa mudança passe despercebida no começo. Mas para quem constrói APIs, bibliotecas, validadores, decorators e ferramentas de desenvolvimento, o impacto pode ser grande. Menos gambiarra, menos confusão com forward references e mais clareza sobre o que exatamente está sendo lido das anotações.

Se você quer continuar acompanhando tendências relevantes da linguagem, veja também nossos conteúdos sobre [Python 3.13 free-threaded](/blog/python-3-13-free-threaded-sem-gil/), [uv no ecossistema Python](/blog/uv-gerenciador-pacotes-python/) e [boas práticas de Python em 2026](/blog/boas-praticas-python-2026/).

Para quem se interessa por sistemas de tipos avançados, <a href="https://kotlin.dev.br/" target="_blank" rel="noopener" onclick="umami.track('portfolio-site-click', { destination: 'kotlin.dev.br' })">Kotlin</a> oferece reified generics e reflection com null safety nativa, e <a href="https://rustlang.com.br/" target="_blank" rel="noopener" onclick="umami.track('portfolio-site-click', { destination: 'rustlang.com.br' })">Rust</a> resolve anotações em tempo de compilação com macros derive — abordagens diferentes para problemas semelhantes ao que o `annotationlib` resolve.
