Introdução
Embora os gerenciadores de contexto (context managers) do Python sejam amplamente utilizados, poucos compreendem o propósito por trás de seu uso. Essas declarações, comumente usadas na leitura e escrita de arquivos, auxiliam a aplicação a conservar a memória do sistema e a melhorar o gerenciamento de recursos, garantindo que recursos específicos fiquem em uso apenas para determinados processos.
Neste laboratório, você aprenderá a usar a declaração with para gerenciamento automático de recursos e, em seguida, criará seus próprios gerenciadores de contexto usando duas abordagens diferentes: uma abordagem baseada em função e uma abordagem baseada em classe.
A declaração with
Nesta etapa, você aprenderá a usar a instrução with com gerenciadores de contexto (context managers) como objetos de arquivo. Um gerenciador de contexto é um objeto que é notificado quando um contexto (um bloco de código) começa e termina. A instrução with cuida desse processo de notificação automaticamente.
Por exemplo, objetos de arquivo são gerenciadores de contexto. Quando um bloco with termina, o objeto de arquivo é fechado automaticamente, mesmo que ocorram erros dentro do bloco. Isso evita perda de dados e vazamento de recursos.
Nota: Se você não está familiarizado com o uso do WebIDE (semelhante ao VS Code), aprenda primeiro neste laboratório.
Vamos ver isso em ação. No explorador de arquivos à esquerda, abra o arquivo main.py. Copie e cole o código a seguir nele. Este código primeiro criará e escreverá em um arquivo, e depois lerá seu conteúdo, tudo usando a instrução with.
## Vamos criar um arquivo para demonstrar a instrução 'with'.
## Primeiro, vamos escrever algum conteúdo em um arquivo.
with open('my_file.txt', 'w') as f:
f.write('This is a test file.')
## Agora, vamos lê-lo de volta usando um gerenciador de contexto.
## O arquivo é fechado automaticamente ao sair do bloco 'with'.
with open('my_file.txt') as f:
file_contents = f.read()
print(file_contents)
## O arquivo é fechado automaticamente aqui, mesmo que um erro tenha ocorrido.
print("\nFile has been read and closed.")
Agora, execute o script a partir do terminal para ver a saída.
python3 main.py
Você deverá ver a seguinte saída, confirmando que o arquivo foi escrito e lido com sucesso. A instrução with garante que my_file.txt seja fechado corretamente após as operações de escrita e leitura.
This is a test file.
File has been read and closed.
Usar uma instrução with é a maneira recomendada de lidar com recursos como arquivos ou conexões de rede, pois torna seu código mais limpo e seguro.
Escrevendo seu próprio gerenciador de contexto
Nesta etapa, você descobrirá como criar um gerenciador de contexto personalizado usando uma função geradora e o decorador @contextlib.contextmanager. Esta é uma maneira concisa de criar gerenciadores de contexto simples.
O código antes da instrução yield é executado ao entrar no bloco with (a lógica de configuração), e o código após a instrução yield é executado ao sair dele (a lógica de limpeza). O valor que é retornado (yielded) pode ser atribuído a uma variável usando a palavra-chave as na declaração with.
Abra o arquivo function_cm.py no explorador de arquivos. Copie o código a seguir para o arquivo.
## Gerenciador de contexto baseado em função usando o decorador contextlib
import contextlib
@contextlib.contextmanager
def context_manager(num):
print('Enter') ## O código antes do yield é executado em __enter__
yield num + 1 ## O valor retornado se torna a variável 'cm'
print('Exit') ## O código após o yield é executado em __exit__
with context_manager(2) as cm: ## cm recebe o valor retornado (3)
print('Right in the middle with cm = {}'.format(cm))
Agora, execute o script no terminal.
python3 function_cm.py
Você verá a seguinte saída. Observe a ordem de execução: o código antes do yield é executado primeiro, depois o código dentro do bloco with, e finalmente o código após o yield.
Enter
Right in the middle with cm = 3
Exit
Esta abordagem é muito útil para criar contextos temporários, como configurar e desativar uma conexão de banco de dados ou alterar temporariamente uma configuração.
Gerenciador de contexto baseado em classe
Nesta etapa, você implementará um gerenciador de contexto como uma classe. Essa abordagem oferece mais controle e é adequada para cenários mais complexos. Para criar um gerenciador de contexto baseado em classe, você deve definir dois métodos especiais: __enter__ e __exit__.
__enter__: Este método é chamado ao entrar na declaraçãowith. Ele deve executar a lógica de configuração (setup). Seu valor de retorno é atribuído à variável apósas, se fornecida.__exit__: Este método é chamado ao sair do blocowith, seja normalmente ou devido a uma exceção. Ele deve executar a lógica de limpeza (cleanup).
Vamos criar um. Abra o arquivo class_cm.py e copie o código a seguir para ele.
## Gerenciador de contexto baseado em classe: implementa os métodos __enter__ e __exit__
class ContextManager:
def __enter__(self, *args, **kwargs): ## Chamado ao entrar no bloco 'with'
print("--enter--")
return self ## Pode retornar o objeto para ser usado como variável 'as'
def __exit__(self, *args): ## Chamado ao sair do bloco 'with'
print("--exit--")
with ContextManager(): ## Chama __enter__, depois __exit__ quando concluído
print("test")
Execute o script no terminal.
python3 class_cm.py
A saída demonstra o fluxo de controle. O método __enter__ é chamado primeiro, seguido pelo código dentro do bloco with, e, finalmente, o método __exit__ é chamado para a limpeza.
--enter--
test
--exit--
A abordagem baseada em classe é poderosa porque permite encapsular lógica complexa de configuração e desativação dentro de um único objeto reutilizável.
Resumo
Parabéns por completar o laboratório! Você aprendeu a gerenciar recursos de forma eficaz em Python usando gerenciadores de contexto (context managers).
Você começou com a declaração with comum para manipulação segura de arquivos. Em seguida, você passou a criar seus próprios gerenciadores de contexto personalizados usando duas abordagens diferentes:
- Uma abordagem baseada em função com o decorador
@contextlib.contextmanager, que é excelente para tarefas simples de configuração (setup) e limpeza (teardown). - Uma abordagem baseada em classe, implementando os métodos
__enter__e__exit__, que é ideal para gerenciamento de recursos mais complexo.
Essas habilidades são cruciais para escrever código Python limpo, confiável e eficiente que lida com recursos adequadamente.



