Gerenciadores de Contexto Personalizados

Em uma postagem anterior, abordamos o conceito de gerenciadores de contexto. Eles são ferramentas importantes para garantir que os recursos em um programa sejam alocados e liberados adequadamente, mesmo quando ocorrem exceções durante sua execução. Embora o Python conte com gerenciadores para lidar com casos gerais, em muitas situações precisamos de soluções personalizadas.
Existem duas formas principais para criar gerenciadores de contexto personalizados, uma baseada em classes e outra em função.
Os gerenciadores de contexto baseados em funções são implementados usando funções geradoras decoradas com o @contextmanager do módulo contextlib.
Já os gerenciadores de contexto baseados em classe são implementados definindo uma classe contendo os métodos __enter__() e __exit__(). Esses gerenciadores são mais flexíveis e podem lidar com cenários complexos. Eles permitem definir métodos e atributos adicionais facilmente. Portanto, neste post, nos concentraremos apenas neles.
Gerenciadores de Contexto Baseados em Classes
Como mencionado anteriormente, gerenciadores de contexto baseados em classes usam a instrução with. Em Python, seu uso prossegue internamente com o auxílio de dois métodos: __enter__() e __exit__(). Além de possibilitarem o gerenciamento de contextos padrão em Python, esses dois métodos também podem ser utilizados para criar gerenciamentos personalizados. Para ilustrar como criar esses gerenciamentos personalizados, apresentaremos alguns exemplos a seguir.
Gerenciador de Contexto Personalizado para Abrir Arquivos
O uso da instrução with para abrir arquivos é bem conhecido. Consequentemente, esse é um bom exemplo para ilustrar como é simples definir um gerenciador de contexto personalizado.
class AbreArquivo:
"""Gerenciador de contexto personalizado para abrir arquivos """
def __init__(self, nome_arquivo, modo):
self.nome_arquivo = nome_arquivo
self.modo = modo
self.file = None # Armazena o objeto do arquivo
def __enter__(self):
self.file = open(self.nome_arquivo, self.modo)
return self.file # Retorna o arquivo aberto para ser usado
def __exit__(self, exc_type, exc_val, exc_traceback):
if self.file:
self.file.close() # Fecha arquivo
No código acima, criamos uma classe para abrir arquivos de forma gerenciada. Ela recebe um nome de arquivo e o modo de abertura (w para write, r para read, etc) como argumentos. No método __enter__() ocorre a abertura e retorno do arquivo. Já o método __exit__() garante seu fechamento. Para usar essa classe personalizada, o procedimento ocorre normalmente com o uso da instrução with.
with AbreArquivo("meu_arquivo.txt", "w") as file:
file.write("Oi, mundo com Python!")
Gerenciador de Contexto de Tempo
Gerenciadores de contexto podem ser usados em múltiplos cenários. Outro exemplo ilustrativo é a sua utilização como gerenciador de contexto de tempo. Este gerenciador mede o tempo de execução do bloco de código dentro da instrução with.
import time
class Temporizador:
"""Gerenciador de contexto de tempo"""
def __init__(self, mensagem):
self.mensagem = mensagem
def __enter__(self):
self.inicio = time.time() # inicia contagem de tempo
return self
def __exit__(self, exc_type, exc_value, exc_traceback):
tempo_consumido = time.time() - self.inicio # termina contagem de tempo
print(f"{self.mensagem} levou {tempo_consumido:.3f} segundo")
Assim como o exemplo anterior, esse gerenciador de contexto personalizado é executado normalmente com a instrução with. Abaixo, temporizamos uma função ilustrativa:
def minha_func():
"""exemplo ilustrativo """
for i in range(2000000):
i + 1
with Temporizador("Executando minha_func()"): # usa gerenciador de contexto de tempo para temporizar uma função
minha_func()
# resultado: Executando minha_func() levou 0.061 segundo
Gerenciador de Contexto de Diretório Temporário
Outra aplicação interessante de gerenciadores de contextos é na criação de diretórios temporários. Um gerenciador de contexto de diretório temporário é utilizado para criar um diretório temporário, executar o bloco de código e, em seguida, remover o diretório temporário e seu conteúdo. Veja como isso pode ser implementado facilmente em Python:
import os
import shutil
import tempfile
class DiretorioTemporario:
"""Grenciador de contexto para criação de diretórios temporários"""
def __enter__(self):
self.temp_dir = tempfile.mkdtemp()
return self.temp_dir # cria diretório temporário
def __exit__(self, exc_type, exc_value, exc_traceback):
shutil.rmtree(self.temp_dir) # deleta diretório temporário
# exemplo de sintaxe para uso da classe DiretorioTemporario
with DiretorioTemporario() as temp_dir:
# Realiza operações no diretório temporário
pass
Veja também:
Concatenações com join() para strings em Python
O que é operador ternário em Python?
F-strings em Strings Multilinhas
Decodificação de strings em Python com decode()
Métodos para Manipular Strings em Python
Módulo Getpass para Prompts de Senhas
Aprenda a comparar textos com Python com Difflib
Módulo textwrap para formatação de textos
Manipulação de arquivos com Python
os.environ: gerenciamento de variáveis de ambiente com Python
Encontrou algum erro ou quer fazer uma sugestão? Por favor, entre em contato usando nosso formulário de contatos.