2.24. Gerenciadores de contexto¶
A instrução with executa um código de configuração, depois um corpo e, então, um código de finalização – com a garantia de que a finalização seja executada mesmo quando o corpo falha no meio do caminho. O par de métodos que fornece a configuração e a finalização é chamado de gerenciador de contexto.
O formato é:
with <expression> as <name>:
<body>
A expressão retorna um gerenciador de contexto. O Python chama seu método __enter__, opcionalmente vincula o resultado a <name>, executa o corpo e, em seguida, chama __exit__ – quer o corpo tenha sido concluído normalmente, quer tenha lançado uma exceção.
__exit__ é executado ao final do bloco, aconteça o que acontecer dentro dele.¶
2.24.1. Usando um gerenciador de contexto¶
O exemplo canônico é abrir um arquivo:
with open("data.txt") as f:
text = f.read()
# f is now closed, even if read() failed
open() retorna um objeto de arquivo que é ele próprio um gerenciador de contexto; __enter__ retorna o arquivo, e __exit__ o fecha. O bloco with torna “sempre fechar o arquivo quando terminar” o comportamento padrão, em vez de algo que o chamador precise lembrar.
2.24.1.1. Múltiplos gerenciadores de contexto¶
Uma única instrução with pode entrar em vários gerenciadores de contexto de uma só vez, separados por vírgulas:
with open("input.txt") as src, open("output.txt", "w") as dst:
dst.write(src.read())
Equivalente a dois blocos with aninhados, mas mais plano. Os gerenciadores são acionados da esquerda para a direita e encerrados em ordem inversa; se o __enter__ do gerenciador à direita lançar uma exceção, o __exit__ do gerenciador à esquerda ainda é executado.
2.24.2. Escrevendo um gerenciador de contexto¶
Qualquer classe com métodos __enter__ e __exit__ funciona como um gerenciador de contexto:
class Section:
def __init__(self, label):
self.label = label
def __enter__(self):
print("---", self.label, "---")
return self
def __exit__(self, exc_type, exc_value, traceback):
print("--- end", self.label, "---")
return False
with Section("setup"):
print("doing the work")
Saída:
--- setup ---
doing the work
--- end setup ---
__exit__ recebe três argumentos descrevendo a exceção que encerrou o bloco, ou três valores None se o bloco foi concluído normalmente. Retornar False (ou None) permite que qualquer exceção se propague após a finalização; retornar True a suprimiria.
Use gerenciadores de contexto para qualquer recurso que tenha um ciclo de vida do tipo “abrir / fechar” ou “adquirir / liberar” – não apenas arquivos. O padrão mantém a limpeza emparelhada com a configuração no ponto em que ambas são introduzidas, de modo que um fechamento esquecido no meio de uma função longa não possa vazar o recurso.