Módulo 6 - Context managers e o with

Ferramentas do contextlib: ExitStack e suppress

9 min de leitura · por Cesar Gargiulo, revisado pela equipe ValorFinal e GuardiaSec · Atualizado em 01/07/2026

O que você vai aprender

  • Usar contextlib.suppress para ignorar exceções específicas com clareza.
  • Entender o problema de gerenciar muitos recursos com with aninhado.
  • Usar contextlib.ExitStack para uma quantidade variável de recursos.
  • Reconhecer quando cada utilitário do contextlib é a escolha certa.

suppress: ignorar exceções com clareza

Às vezes você quer tentar uma operação e simplesmente ignorar um erro específico se ele acontecer. O padrão antigo é um try, except com um pass no corpo, que é verboso e fácil de exagerar, capturando erros demais. O contextlib.suppress expressa a mesma intenção de forma direta e legível: dentro do bloco, se ocorrer uma das exceções indicadas, ela é engolida em silêncio e o programa segue depois do bloco. Fora essas, tudo continua subindo normalmente.

from contextlib import suppress
import os

# Antes: verboso
try:
    os.remove("temporario.txt")
except FileNotFoundError:
    pass

# Depois: claro e enxuto
with suppress(FileNotFoundError):
    os.remove("temporario.txt")
# Se o arquivo nao existir, o erro e ignorado e o programa segue.

suppress substitui o try, except, pass, deixando a intenção explícita.

Um cuidado: o suppress é para casos em que ignorar o erro é mesmo a decisão certa, como apagar um arquivo que talvez já não exista. Ele não deve virar um tapete para esconder falhas de verdade. E indique sempre os tipos específicos que quer ignorar, nunca Exception genérica, pelo mesmo motivo de sempre: capturar demais esconde bugs. Bem usado, o suppress deixa a intenção de ignorar aquele erro em particular explícita para quem lê.

O problema de muitos recursos ao mesmo tempo

Abrir dois arquivos no mesmo with é fácil: basta separar por vírgula. Mas e quando o número de recursos não é fixo? Imagine que você precisa abrir uma lista de arquivos cujo tamanho só se conhece na hora, todos dentro de um único bloco, com a garantia de que todos serão fechados. Com with comum isso fica impossível de escrever de forma limpa, porque você não sabe quantos as encadear. Aninhar with um dentro do outro em profundidade variável também não é viável.

# Isto so funciona com um numero FIXO de arquivos:
with open("a.txt") as fa, open("b.txt") as fb:
    ...

# E se a lista de nomes so for conhecida em tempo de execucao?
nomes = ["a.txt", "b.txt", "c.txt"]  # tamanho variavel
# Nao da para encadear as virgulas dinamicamente. Precisamos de outra ferramenta.

O with com vírgulas só resolve um número fixo de recursos, conhecido no código.

ExitStack: recursos dinâmicos sob controle

A resposta é o contextlib.ExitStack. Ele é um context manager que serve de pilha para outros context managers. Dentro do bloco, você usa stack.enter_context para adicionar cada recurso à pilha, e recebe de volta o que aquele recurso entregaria no as. Quando o bloco do ExitStack termina, ele fecha todos os recursos que empilhou, na ordem inversa da abertura, com erro ou sem erro. Assim você gerencia uma quantidade variável de recursos com a mesma garantia do with de sempre.

from contextlib import ExitStack

nomes = ["a.txt", "b.txt", "c.txt"]

with ExitStack() as stack:
    arquivos = [stack.enter_context(open(nome)) for nome in nomes]
    # todos os arquivos estao abertos e disponiveis aqui
    for arquivo in arquivos:
        primeira_linha = arquivo.readline()
        print(primeira_linha.strip())
# ao sair, o ExitStack fecha todos os arquivos, na ordem inversa

O ExitStack abre uma lista de tamanho variável e garante o fechamento de todos.

Repare como o enter_context devolve o arquivo aberto, que você guarda na lista para usar. Se a abertura de um dos arquivos falhar no meio do caminho, o ExitStack já fecha os que conseguiu abrir antes, sem deixar nenhum vazando. É a mesma segurança do with, agora para um número dinâmico de recursos. Junto com o suppress e o contextmanager, o ExitStack completa um conjunto de ferramentas que cobre praticamente qualquer necessidade de gestão de recursos em Python.

Teste rápido

Em que situação o contextlib.ExitStack é a ferramenta certa?

Perguntas frequentes

O suppress não é perigoso por esconder erros?
Só se usado errado. Ele é seguro quando você indica os tipos específicos que faz sentido ignorar, como um FileNotFoundError ao apagar um arquivo que talvez não exista. O perigo é passar Exception genérica, que engoliria qualquer falha. Usado com tipos precisos, o suppress torna a intenção de ignorar aquele erro clara, melhor que um try, except, pass.
Qual a diferença entre suppress e um try, except comum?
O suppress é açúcar para o caso específico de capturar uma exceção e não fazer nada, apenas seguir em frente. Se você precisa reagir ao erro, registrar, tratar, tentar outra coisa, então o try, except comum é o certo, porque o suppress só ignora. Escolha o suppress quando a ação desejada for de fato ignorar aquele erro.
O ExitStack fecha os recursos em qual ordem?
Na ordem inversa da que foram abertos, igual a um with aninhado. O último recurso empilhado é o primeiro a ser fechado. Isso importa quando os recursos dependem uns dos outros: um recurso aberto depois pode depender de um aberto antes, então fechá-lo primeiro é a ordem segura.
Posso misturar recursos diferentes no mesmo ExitStack?
Sim. O ExitStack aceita qualquer context manager via enter_context: arquivos, locks, conexões, gerenciadores que você mesmo criou com yield. Todos vão para a mesma pilha e são limpos juntos ao sair. Isso é útil quando um bloco precisa coordenar recursos de tipos variados de uma vez.
O que acontece se abrir um recurso falhar no meio do ExitStack?
O ExitStack fecha os recursos que já tinham sido abertos e empilhados até ali, e depois deixa a exceção subir. Ou seja, nenhum recurso fica vazando por causa de uma falha parcial. Essa é justamente a vantagem sobre abrir tudo à mão: a limpeza dos que deram certo é garantida mesmo quando um dá errado.

Fontes

Seu progresso fica salvo neste aparelho. Assinantes sincronizam entre os aparelhos.