contextlib: Crie Seu Próprio Context Manager
A instrução with é um dos recursos mais expressivos do Python. Ela garante que a lógica de setup e cleanup rode corretamente, mesmo quando ocorrem exceções.
A maioria das pessoas usa isso com arquivos ou conexões de banco de dados. Por baixo dos panos, context managers substituem blocos repetitivos de try/finally por uma abstração mais limpa.
Com contextlib, você pode criar seus próprios context managers e aplicar o mesmo padrão a qualquer problema.
Por Que Context Managers Existem
Sem um context manager, você provavelmente escreveria algo assim:
resource = acquire()
try:
process(resource)
finally:
release(resource)
Funciona, mas é repetitivo e fácil de esquecer.
A instrução with formaliza esse padrão. Um context manager define o que acontece ao entrar e ao sair de um bloco de código.
A Abordagem Tradicional: enter e exit
Você pode criar um context manager definindo dois métodos especiais:
class Timer:
def __enter__(self):
print("Starting")
return self
def __exit__(self, exc_type, exc, tb):
print("Finished")
Isso é poderoso, mas verboso.
Para casos mais simples, contextlib oferece uma solução mais limpa.
Usando @contextmanager
O decorator @contextmanager permite definir a lógica de setup e cleanup em torno de um único yield.
O código antes do yield roda ao entrar no bloco.
O código depois do yield roda ao sair do bloco, mesmo que uma exceção aconteça.
Exemplo:
import time
import tracemalloc
from contextlib import contextmanager
@contextmanager
def performance_tracker(label="Block"):
start_time = time.perf_counter()
tracemalloc.start()
try:
yield
finally:
elapsed = time.perf_counter() - start_time
current, peak = tracemalloc.get_traced_memory()
tracemalloc.stop()
print(f"{label} took {elapsed:.4f}s | Peak memory: {peak / 1024:.1f} KB")
Uso:
with performance_tracker("Data Processing"):
data = [x ** 2 for x in range(1_000_000)]
O código dentro do bloco roda normalmente. Quando o bloco termina, o cleanup e o relatório acontecem automaticamente.
Por Que Isso É Poderoso
Context managers customizados permitem:
- Medir tempo de execução de forma consistente
- Medir uso de memória
- Encapsular logs ou métricas
- Gerenciar estado temporário com segurança
- Isolar preocupações transversais de forma limpa
Em fluxos com muitos dados, esse padrão ajuda a monitorar transformações sem alterar a lógica principal.
Eu criei um pequeno context de medição de performance em um projeto e acabei usando em tudo. É uma daquelas utilidades que valem a pena na hora.
Boas Práticas
- Sempre coloque o cleanup dentro de
finally - Mantenha cada context manager focado em uma responsabilidade
- Evite embutir lógica de negócio complexa dentro dele
- Use labels descritivos para observabilidade
Consideração Final
contextlib estende o poder do with para além de arquivos e conexões.
Ao encapsular setup e teardown em uma abstração reutilizável, você reduz repetição e melhora a confiabilidade.
Context managers não são apenas conveniência sintática. Eles são uma forma disciplinada de gerenciar recursos e comportamentos transversais em Python.