contextvars no Python: contexto assíncrono

Publicado em: 28/08/2026
Tempo de leitura: 6 minutos
Close-up view of a computer screen displaying code in a software development environment.

O módulo contextvars permite armazenar informações associadas ao contexto atual de execução. Diferente de uma variável global, um ContextVar pode ter valores distintos em tasks assíncronas, threads e contextos copiados. Isso é útil para IDs de requisição, tracing, usuário atual, locale, transações e dados de observabilidade que precisam acompanhar uma cadeia de chamadas sem ser passados manualmente em todos os argumentos.

Context variables não substituem parâmetros explícitos para dados de negócio. Elas são adequadas para contexto transversal e controlado. Valores ocultos demais dificultam testes e compreensão. Defina ownership, momento de configuração, restauração e limites de lifecycle.

Crie um ContextVar

Declare a variável normalmente no nível do módulo.

from contextvars import ContextVar

request_id = ContextVar("request_id")

O nome aparece em diagnóstico e representação. Use um identificador claro e estável.

Defina e leia um valor

set() associa um valor ao contexto atual e get() recupera.

request_id.set("req-123")
print(request_id.get())

O valor não é simplesmente uma global compartilhada; cada contexto pode possuir sua própria associação.

Valores padrão

Um default pode ser definido no construtor.

locale_atual = ContextVar("locale_atual", default="pt-BR")

Use default apenas quando a ausência for realmente válida. Para valores obrigatórios, deixar sem default ajuda a detectar configuração esquecida.

LookupError

Chamar get() sem valor e sem default gera LookupError.

try:
    identificador = request_id.get()
except LookupError:
    identificador = "sem-contexto"

Não esconda automaticamente um erro quando o contexto deveria ser obrigatório.

Tokens

set() retorna um Token que representa o estado anterior.

token = request_id.set("req-456")
try:
    executar()
finally:
    request_id.reset(token)

O padrão try/finally evita que o valor vaze para trabalho executado depois no mesmo contexto.

Restaure, não apenas limpe

reset(token) restaura o estado anterior, que pode ser outro valor ou ausência.

Definir None não é equivalente: pode destruir um valor externo que deveria voltar depois do bloco.

Crie um context manager

Um wrapper torna o padrão de set/reset reutilizável.

from contextlib import contextmanager

@contextmanager
def usar_request_id(valor):
    token = request_id.set(valor)
    try:
        yield
    finally:
        request_id.reset(token)

Consulte contextlib no Python para managers síncronos e assíncronos.

Integração com asyncio

Tasks criadas em um contexto normalmente recebem uma cópia apropriada do contexto atual.

import asyncio

async def worker(nome):
    print(nome, request_id.get())

async def main():
    token = request_id.set("req-main")
    try:
        await asyncio.gather(worker("a"), worker("b"))
    finally:
        request_id.reset(token)

Cada task pode alterar seu próprio valor sem sobrescrever o contexto das outras.

Criação de tasks

O momento em que uma task é criada influencia o contexto capturado.

Defina o valor antes de criar a task quando ela precisa herdar a associação. Para controle explícito, use APIs da versão alvo que aceitem um contexto.

Não use threading.local em código async

threading.local() separa dados por thread, mas várias tasks assíncronas compartilham a mesma thread.

ContextVar foi projetado para manter isolamento lógico entre essas tasks.

Threads

Cada thread possui sua própria pilha de contextos. Um valor não aparece automaticamente em uma nova thread.

Se um worker precisa do contexto do caller, copie e execute explicitamente ou passe os dados como argumentos.

copy_context

copy_context() cria uma cópia rasa do contexto atual.

from contextvars import copy_context

contexto = copy_context()
contexto.run(executar_funcao)

A cópia registra associações de variáveis, mas objetos mutáveis usados como valores continuam sendo os mesmos objetos.

Propague para um executor

Ao enviar trabalho a uma thread, capture o contexto antes.

contexto = copy_context()
futuro = executor.submit(contexto.run, processar, item)

Não execute simultaneamente o mesmo objeto Context em várias threads. Crie uma cópia para cada submissão quando necessário.

Valores mutáveis

Colocar um dicionário ou lista em um ContextVar não torna o objeto imutável ou isolado.

Prefira valores imutáveis ou crie uma cópia antes de modificar. Caso contrário, dois contextos podem compartilhar a mesma estrutura interna.

IDs de requisição

Middleware pode definir o ID ao entrar e restaurar ao sair.

def atender(request):
    token = request_id.set(request.id)
    try:
        return processar(request)
    finally:
        request_id.reset(token)

Mesmo em caso de exceção, a associação anterior volta corretamente.

Logging

Filtros ou adapters de logging podem ler o valor atual e adicioná-lo aos registros.

class ContextFilter(logging.Filter):
    def filter(self, record):
        record.request_id = request_id.get("-")
        return True

Evite armazenar tokens, senhas e dados pessoais no contexto de log.

Tracing

Trace ID e span ID são exemplos comuns de contexto transversal.

Bibliotecas de observabilidade podem usar contextvars internamente. Integre com a API oficial para não criar duas fontes de verdade.

Locale e timezone

Uma aplicação pode armazenar preferência de locale ou timezone por requisição.

O valor precisa ser validado e resetado. Funções puras que recebem locale explicitamente continuam mais fáceis de testar.

Transações

Um identificador ou objeto de sessão pode ser contextual, mas conexões e transações têm lifecycle crítico.

Não esconda commit, rollback e fechamento. Combine contextvars com context managers e ownership explícito.

Callbacks

O contexto em que um callback executa pode depender de quando e como ele foi registrado.

Não presuma propagação em bibliotecas de terceiros. Faça um teste de integração ou capture o contexto explicitamente.

Background tasks

Uma tarefa em background não deve herdar automaticamente todo o contexto de uma requisição, especialmente credenciais e objetos grandes.

Crie um contexto limpo ou copie somente os campos necessários.

Context.run

Context.run(callable, ...) entra no contexto, executa a função e sai depois.

resultado = contexto.run(funcao, argumento)

Uma exceção propaga normalmente, e o contexto anterior da thread é restaurado.

Inspecione um contexto

Um objeto Context pode ser tratado como mapping para diagnóstico.

for variavel, valor in copy_context().items():
    print(variavel.name, valor)

Não registre valores completos sem classificação de sensibilidade.

Performance

Operações de contexto são eficientes para uso transversal comum, mas não devem substituir variáveis locais em loops internos.

Meça antes de colocar dezenas de leituras em caminhos extremamente quentes.

APIs públicas

Uma biblioteca pode usar contextvars internamente, mas deve documentar como o contexto é definido e restaurado.

Evite exigir que usuários manipulem tokens internos ou dependam do nome de uma variável privada.

Testes

Todo teste deve estabelecer o contexto que usa e restaurá-lo no final.

token = request_id.set("teste")
try:
    assert executar() == esperado
finally:
    request_id.reset(token)

Teste tasks concorrentes com valores diferentes para detectar vazamentos.

Isolamento entre testes

Fixtures que esquecem o reset podem contaminar casos seguintes executados na mesma thread.

Use context managers ou fixtures com cleanup garantido.

Segurança

Contexto implícito pode transportar identidade e autorização. Nunca confie apenas em um valor contextual sem validar a operação.

Reduza a propagação para background jobs e não exponha o conteúdo em mensagens de erro públicas.

Erros comuns

Os erros mais frequentes são usar global ou threading.local em asyncio, esquecer reset(), definir None em vez de restaurar token, armazenar objetos mutáveis, presumir propagação para threads e usar contexto oculto para dados de negócio.

Conclusão

contextvars fornece contexto local à execução para threads e tasks assíncronas. Use ContextVar para dados transversais, tokens para restauração e copy_context() para propagação explícita.

Mantenha valores pequenos, evite segredos, teste isolamento e continue usando parâmetros explícitos para regras de negócio. Consulte a documentação oficial de contextvars e contextlib no Python.

Compartilhe:

Facebook
WhatsApp
Twitter
LinkedIn

Conteúdo do artigo

    Artigos relacionados

    Person writing appointments on a calendar with a blue pen. High angle view.
    Python Avançado
    Foto de perfil de Leandro Hirt da Academify

    sched no Python: agende eventos

    Aprenda sched no Python para agendar eventos, usar prioridades, cancelar tarefas, criar recorrência sem drift e integrar executores.

    Ler mais

    Tempo de leitura: 6 minutos
    28/08/2026
    Close-up of a vibrant yellow python coiled with textured scales in vibrant light.
    Python Avançado
    Foto de perfil de Leandro Hirt da Academify

    bisect no Python: listas ordenadas

    Aprenda bisect no Python para busca binária, inserção ordenada, duplicatas, funções key, faixas, rankings e sincronização segura.

    Ler mais

    Tempo de leitura: 5 minutos
    28/08/2026
    A developer typing code on a laptop with a Python book beside in an office.
    Python Avançado
    Foto de perfil de Leandro Hirt da Academify

    heapq no Python: filas de prioridade

    Aprenda heapq no Python para filas de prioridade, top-k, merge, empates, atualização de prioridades, lazy deletion e backpressure.

    Ler mais

    Tempo de leitura: 5 minutos
    28/08/2026
    A detailed close-up of a sleek computer keyboard with numerical keypad.
    Python Avançado
    Foto de perfil de Leandro Hirt da Academify

    array no Python: números compactos

    Aprenda array no Python para armazenar números compactos, trabalhar com typecodes, bytes, arquivos, memoryview e validação portátil.

    Ler mais

    Tempo de leitura: 5 minutos
    28/08/2026
    Chic portrait of a woman wearing trendy sunglasses reflecting numbers, captured in a modern setting.
    Python Avançado
    Foto de perfil de Leandro Hirt da Academify

    struct no Python: dados binários

    Aprenda struct no Python para empacotar dados binários, controlar endianness, offsets, padding, buffers, sockets e validação segura.

    Ler mais

    Tempo de leitura: 5 minutos
    28/08/2026
    A young girl exploring a library's card catalog, symbolizes research and curiosity.
    Python Avançado
    Foto de perfil de Leandro Hirt da Academify

    mmap no Python: arquivos na memória

    Aprenda mmap no Python para mapear arquivos, buscar bytes, editar regiões, compartilhar memória, usar offsets e evitar erros de sincronização.

    Ler mais

    Tempo de leitura: 7 minutos
    28/08/2026