contextvars no Python: contexto assíncrono

Publicado em: 11/08/2026
Tempo de leitura: 6 minutos
Fluxo de dados em rede representando contexto assíncrono com contextvars no Python

O módulo contextvars mantém valores locais ao contexto de execução. Ele resolve um problema comum em aplicações concorrentes: disponibilizar informações como ID da requisição, usuário atual, tenant, locale ou metadados de tracing sem passar argumentos por todas as funções e sem permitir que o estado de uma tarefa vaze para outra.

Em código síncrono com threads, threading.local() pode atender alguns casos. Em asyncio, várias tarefas compartilham a mesma thread e alternam a execução. Variáveis de contexto acompanham a tarefa lógica e são propagadas pelas APIs assíncronas do Python.

Criar uma ContextVar

Crie variáveis no nível do módulo, não dentro de closures. Objetos Context mantêm referências fortes às variáveis, e criá-las dinamicamente pode impedir coleta de lixo.

from contextvars import ContextVar

request_id: ContextVar[str] = ContextVar("request_id")
usuario_atual: ContextVar[str | None] = ContextVar(
    "usuario_atual", default=None
)

O nome serve para depuração e introspecção. O parâmetro default é opcional e deve ser coerente com o tipo esperado.

Ler um valor

get() procura o valor no contexto atual. A prioridade é: padrão passado ao método, padrão definido na criação e, se nenhum existir, LookupError.

print(usuario_atual.get())

try:
    print(request_id.get())
except LookupError:
    print("request_id ainda não definido")

Para dados obrigatórios, não definir um default pode revelar erros de integração mais cedo. Para dados realmente opcionais, um valor padrão explícito simplifica o uso.

Definir e restaurar com token

set() altera o valor no contexto atual e devolve um Token. O token restaura exatamente o estado anterior.

token = request_id.set("req-123")
try:
    processar()
finally:
    request_id.reset(token)

Use try/finally para garantir restauração mesmo quando ocorre uma exceção. O mesmo token não pode ser usado duas vezes e pertence à variável que o criou.

Token como context manager no Python 3.14

Desde Python 3.14, o token retornado por set() implementa o protocolo de context manager.

with request_id.set("req-456"):
    print(request_id.get())

# valor anterior restaurado automaticamente

Esse formato aproxima a definição temporária do escopo em que ela vale. Para código compatível com versões anteriores, mantenha set(), try/finally e reset().

Isolamento em asyncio

Quando uma task é criada, o contexto atual é copiado para ela. Alterações posteriores dentro de uma tarefa ficam isoladas das demais.

import asyncio
from contextvars import ContextVar

nome = ContextVar("nome")

async def trabalho(valor):
    with nome.set(valor):
        await asyncio.sleep(0.01)
        return nome.get()

async def main():
    resultados = await asyncio.gather(
        trabalho("A"),
        trabalho("B"),
    )
    print(resultados)

asyncio.run(main())

Mesmo com alternância após o await, cada tarefa lê seu próprio valor.

ContextVar não é variável global comum

O objeto ContextVar é global, mas seu valor depende do contexto. Guardar o valor também em uma variável global comum destrói o isolamento.

Evite usar contexto para dados de domínio que deveriam ser argumentos explícitos. Ele é mais adequado a metadados transversais usados por muitas camadas.

Request ID em logs

request_id = ContextVar("request_id", default="-")

def log(mensagem):
    print(f"[{request_id.get()}] {mensagem}")

async def tratar_requisicao(id_requisicao):
    with request_id.set(id_requisicao):
        log("início")
        await chamar_servico()
        log("fim")

Bibliotecas de logging podem usar filtros ou adaptadores que consultam a variável. Não coloque segredos ou dados pessoais desnecessários em logs.

Estado de tenant ou usuário

Aplicações multitenant podem disponibilizar o tenant atual por contexto, mas toda consulta ao banco ainda deve aplicar filtros e autorização. A variável facilita propagação; ela não cria uma barreira de segurança.

Defina o valor na borda da requisição, valide o usuário e restaure no final. Teste explicitamente tarefas criadas antes e depois da definição.

copy_context

copy_context() copia o contexto atual com complexidade O(1), independentemente da quantidade de variáveis.

from contextvars import copy_context

ctx = copy_context()
for var, valor in ctx.items():
    print(var.name, valor)

A cópia pode ser executada em outro ponto com ctx.run(funcao, *args). Alterações feitas dentro dela ficam no objeto Context, não no contexto externo.

Executar código em um contexto específico

ctx = copy_context()

def tarefa():
    request_id.set("isolado")
    return request_id.get()

resultado = ctx.run(tarefa)

Não é permitido entrar simultaneamente no mesmo Context mais de uma vez, inclusive a partir de outra thread. Isso gera RuntimeError. Depois de sair, ele pode ser reutilizado.

Propagação para threads

Cada thread possui sua própria pilha efetiva de contextos. Ao enviar trabalho para um executor, a propagação pode depender da API e da versão. Quando precisar de comportamento explícito, capture com copy_context() e execute com ctx.run().

ctx = copy_context()
futuro = executor.submit(ctx.run, funcao)

Não compartilhe o mesmo contexto simultaneamente entre vários trabalhos. Crie cópias separadas.

Diferença para threading.local

threading.local() isola por thread física. Em um event loop, centenas de tasks podem viver na mesma thread, então todas enxergariam o mesmo armazenamento local à thread. ContextVar acompanha o contexto lógico e funciona com asyncio.

Em bibliotecas que podem ser usadas em código concorrente, variáveis de contexto normalmente são a opção correta para estado contextual.

Defaults mutáveis

Evite defaults mutáveis compartilhados, como listas e dicionários. A variável isola a referência, mas mutações no mesmo objeto continuam visíveis.

# evite
erros = ContextVar("erros", default=[])

# prefira criar um valor por escopo
with erros.set([]):
    erros.get().append("falha")

Objetos imutáveis, IDs e dataclasses congeladas reduzem surpresas.

Tokens e ordem de restauração

Definições podem ser aninhadas. Restaure em ordem inversa, como uma pilha.

t1 = request_id.set("externo")
t2 = request_id.set("interno")
request_id.reset(t2)
request_id.reset(t1)

Usar o token errado ou reutilizá-lo gera erro. Context managers do Python 3.14 tornam a ordem mais visível.

Contexto em callbacks e tarefas

Callbacks normalmente executam no contexto capturado pela API que os agendou. Ainda assim, frameworks podem definir regras próprias. Integrações devem ser testadas com tarefas, executores, threads e callbacks reais.

Evite assumir que um objeto criado em uma tarefa sempre executará no mesmo contexto se uma biblioteca transfere trabalho para outro runtime.

Testar isolamento

async def teste_isolamento():
    async def ler(valor):
        with request_id.set(valor):
            await asyncio.sleep(0)
            return request_id.get()

    a, b = await asyncio.gather(ler("A"), ler("B"))
    assert (a, b) == ("A", "B")

Teste também exceções, cancelamento, criação de subtasks e execução em thread. Após cada teste, confirme que o valor anterior foi restaurado.

Não usar como contêiner de dependências

Colocar banco, cliente HTTP e serviços inteiros no contexto esconde dependências e dificulta testes. Passe dependências principais explicitamente. Reserve ContextVar para informações contextuais pequenas e transversais.

Erros frequentes

  • Criar ContextVars dentro de closures.
  • Esquecer de restaurar o token.
  • Usar default mutável compartilhado.
  • Tratar contexto como autorização.
  • Esperar que threading.local() isole tasks asyncio.
  • Compartilhar o mesmo Context simultaneamente.
  • Esconder dependências importantes no contexto.

Boas práticas

  • Declare ContextVars no nível do módulo.
  • Use nomes úteis para depuração.
  • Restaure valores com token ou context manager.
  • Prefira dados pequenos e imutáveis.
  • Capture contexto explicitamente ao mudar de thread.
  • Teste cancelamento e concorrência.
  • Preserve autorização e validação fora do contexto.

Conteúdos relacionados

Veja ExitStack, inspect, faulthandler, traceback e operator.

Consulte a documentação oficial do contextvars e a PEP 567.

Conclusão

contextvars fornece estado contextual isolado para código síncrono e assíncrono. Ele é ideal para IDs de requisição, tracing, locale e pequenos metadados transversais. O uso seguro exige escopos claros, restauração garantida, defaults imutáveis e testes de propagação entre tarefas e threads.

Compartilhe:

Facebook
WhatsApp
Twitter
LinkedIn

Conteúdo do artigo

    Artigos relacionados

    Código de programação representando operações como funções com operator no Python
    Python Avançado
    Foto de perfil de Leandro Hirt da Academify

    operator no Python: operações como funções

    Aprenda operator no Python para usar operações como funções, ordenar campos, acessar itens, chamar métodos e trabalhar com pipelines funcionais.

    Ler mais

    Tempo de leitura: 5 minutos
    11/08/2026
    Alfabeto tridimensional representando normalização Unicode com unicodedata no Python
    Python Avançado
    Foto de perfil de Leandro Hirt da Academify

    unicodedata no Python: normalize Unicode

    Aprenda unicodedata no Python para normalizar Unicode, consultar nomes, categorias, números, caracteres combinantes e largura de exibição.

    Ler mais

    Tempo de leitura: 6 minutos
    11/08/2026
    Rede de servidores representando gerenciamento de recursos com ExitStack no Python
    Python Avançado
    Foto de perfil de Leandro Hirt da Academify

    ExitStack no Python: gerencie recursos

    Aprenda ExitStack no Python para gerenciar arquivos, conexões e limpezas dinâmicas com segurança e ordem previsível.

    Ler mais

    Tempo de leitura: 6 minutos
    11/08/2026
    Pasta com cadeado representando tipos e permissões com stat no Python
    Python Avançado
    Foto de perfil de Leandro Hirt da Academify

    stat no Python: tipos e permissões

    Aprenda stat no Python para interpretar tipos de arquivo, permissões, links, timestamps, atributos do Windows e flags de Unix com

    Ler mais

    Tempo de leitura: 5 minutos
    10/08/2026
    Notebook com código representando documentação automática com pydoc no Python
    Python Avançado
    Foto de perfil de Leandro Hirt da Academify

    pydoc no Python: documentação automática

    Aprenda pydoc no Python para gerar ajuda no terminal, HTML e servidor local a partir de docstrings, com segurança ao

    Ler mais

    Tempo de leitura: 7 minutos
    10/08/2026
    Teclado internacional representando números, moedas e datas com locale no Python
    Python Avançado
    Foto de perfil de Leandro Hirt da Academify

    locale no Python: números, moedas e datas

    Aprenda locale no Python para formatar e interpretar números, moedas, datas e ordenação cultural sem erros de concorrência.

    Ler mais

    Tempo de leitura: 8 minutos
    09/08/2026