Context Managers
with, __enter__, __exit__ e contextlib
Context managers são objetos que definem o protocolo de entrada e saída de um bloco with. Quando o bloco termina (com ou sem exceção), o método __exit__ é chamado automaticamente, garantindo limpeza de recursos como arquivos, conexões e locks.
__enter__ é chamado ao entrar no with e retorna o objeto disponível na cláusula as. __exit__ recebe informações sobre qualquer exceção ocorrida — se retornar True, a exceção é suprimida; se retornar None/False, a exceção se propaga.
contextlib.contextmanager permite criar context managers com generators usando yield, sem precisar de uma classe completa.
import contextlib
import time
# Context manager com classe
class Temporizador:
def __enter__(self):
self.inicio = time.time()
return self # disponível no "as"
def __exit__(self, tipo_exc, valor_exc, tb):
self.duracao = time.time() - self.inicio
print(f"Durou {self.duracao:.4f}s")
return False # não suprimir exceções
with Temporizador() as t:
time.sleep(0.1)
# Durou 0.1001s
# Context manager com generator
@contextlib.contextmanager
def conexao_db(url):
print(f"Conectando a {url}")
conn = {"url": url, "ativo": True}
try:
yield conn # ponto de pausa — executa o bloco with
finally:
conn["ativo"] = False
print("Conexão fechada")
with conexao_db("postgresql://localhost/db") as conn:
print(f"Usando: {conn}")
# suppress — suprimir exceções específicas
with contextlib.suppress(FileNotFoundError):
open("arquivo_que_nao_existe.txt")
# Sem erro! A exceção é suprimida
# Múltiplos context managers em um with
with open("a.txt") as f1, open("b.txt") as f2:
dados = f1.read() + f2.read()Use @contextmanager para context managers simples e classe completa quando precisar de estado persistente ou herança.