Resumo : neste tutorial, você aprenderá sobre os gerenciadores de contexto Python e como usá-los de forma eficaz
Introdução aos gerenciadores de contexto Python
Um gerenciador de contexto é um objeto que define um contexto de tempo de execução em execução na with
instrução.
Vamos começar com um exemplo simples para entender o conceito de gerenciador de contexto.
Suponha que você tenha um arquivo chamado data.txt
que contém um número inteiro 100
.
O programa a seguir lê o data.txt
arquivo, converte seu conteúdo em um número e mostra o resultado na saída padrão:
f = open('data.txt')
data = f.readlines()
# convert the number to integer and display it
print(int(data[0]))
f.close()
Linguagem de código: Python ( python )
O código é simples e direto.
No entanto, data.txt
pode conter dados que não podem ser convertidos em um número. Nesse caso, o código resultará em uma exceção.
Por exemplo, se data.txt
contiver a string '100'
em vez do número 100, você receberá o seguinte erro:
ValueError: invalid literal for int() with base 10: "'100'"
Linguagem de código: Python ( python )
Devido a esta exceção, o Python pode não fechar o arquivo corretamente.
Para corrigir isso, você pode usar a try...except...finally
instrução:
try:
f = open('data.txt')
data = f.readlines()
# convert the number to integer and display it
print(int(data[0]))
except ValueError as error:
print(error)
finally:
f.close()
Linguagem de código: Python ( python )
Como o código no finally
bloco sempre é executado, o código sempre fechará o arquivo corretamente.
Esta solução funciona conforme o esperado. No entanto, é bastante detalhado.
Portanto, Python fornece uma maneira melhor que permite fechar automaticamente o arquivo após concluir o processamento.
É aqui que entram em jogo os gerenciadores de contexto .
A seguir mostramos como usar um gerenciador de contexto para processar o data.txt
arquivo:
with open('data.txt') as f:
data = f.readlines()
print(int(data[0])
Linguagem de código: Python ( python )
Neste exemplo, usamos a open()
função com a with
instrução. Após o with
bloco, o Python será fechado automaticamente.
with
Instrução Python
Aqui está a sintaxe típica da with
instrução:
with context as ctx:
# use the the object
# context is cleaned up
Linguagem de código: Python ( python )
Como funciona.
- Quando Python encontra a
with
instrução, ele cria um novo contexto. O contexto pode opcionalmente retornar um arquivoobject
. - Após o
with
bloco, o Python limpa o contexto automaticamente. - O escopo do
ctx
tem o mesmo escopo dawith
declaração. Isso significa que você pode acessarctx
dentro e depois dawith
instrução.
O seguinte mostra como acessar a f
variável após a with
instrução:
with open('data.txt') as f:
data = f.readlines()
print(int(data[0]))
print(f.closed) # True
Linguagem de código: Python ( python )
Protocolo gerenciador de contexto Python
Os gerenciadores de contexto Python funcionam com base no protocolo do gerenciador de contexto .
O protocolo gerenciador de contexto possui os seguintes métodos:
__enter__()
– configure o contexto e opcionalmente retorne algum objeto__exit__()
– limpe o objeto.
Se você deseja que uma classe suporte o protocolo do gerenciador de contexto, você precisa implementar esses dois métodos.
Suponha que ContextManager
seja uma classe que suporta o protocolo do gerenciador de contexto.
A seguir mostramos como usar a ContextManager
classe:
with ContextManager() as ctx:
# do something
# done with the context
Linguagem de código: Python ( python )
Quando você usa ContextManager
class com a with
instrução, Python cria implicitamente uma instância da ContextManager
classe ( instance
) e chama automaticamente __enter__()
o método nessa instância.
O __enter__()
método pode opcionalmente retornar um objeto. Nesse caso, o Python atribui ao objeto retornado o ctx
.
Observe que isso ctx
faz referência ao objeto retornado pelo __enter__()
método. Não faz referência à instância da ContextManager
classe.
Se ocorrer uma exceção dentro do bloco with ou após o with
bloco, o Python chama o __exit__()
método no instance
objeto.
Funcionalmente, a with
declaração é equivalente à seguinte try...finally
declaração:
instance = ContextManager()
ctx = instance.__enter__()
try:
# do something with the txt
finally:
# done with the context
instance.__exit__()
Linguagem de código: Python ( python )
O método __enter__()
No __enter__()
método, você pode realizar as etapas necessárias para configurar o contexto.
Opcionalmente, você pode retornar um objeto do __enter__()
método.
O método __exit__()
Python sempre executa o __exit__()
método mesmo se ocorrer uma exceção no with
bloco.
O __exit__()
método aceita três argumentos: tipo de exceção, valor de exceção e objeto de rastreamento. Todos esses argumentos serão válidos None
se nenhuma exceção ocorrer.
def __exit__(self, ex_type, ex_value, ex_traceback):
...
Linguagem de código: Python ( python )
O __exit__()
método retorna um valor booleano, True
ou False
.
Se o valor de retorno for True, o Python tornará qualquer exceção silenciosa. Caso contrário, não silencia a exceção.
Aplicativos gerenciadores de contexto Python
Como você pode ver no exemplo anterior, o uso comum de um gerenciador de contexto é abrir e fechar arquivos automaticamente.
No entanto, você pode usar gerenciadores de contexto em muitos outros casos:
1) Abrir – Fechar
Se quiser abrir e fechar um recurso automaticamente, você pode usar um gerenciador de contexto.
Por exemplo, você pode abrir um soquete e fechá-lo usando um gerenciador de contexto.
2) Bloquear – liberar
Os gerenciadores de contexto podem ajudá-lo a gerenciar bloqueios de objetos de maneira mais eficaz. Eles permitem que você adquira um bloqueio e libere-o automaticamente.
3) Iniciar – parar
Os gerenciadores de contexto também ajudam você a trabalhar com um cenário que requer as fases de início e parada.
Por exemplo, você pode usar um gerenciador de contexto para iniciar um cronômetro e pará-lo automaticamente.
3) Alterar – redefinir
Os gerenciadores de contexto podem trabalhar com cenários de mudança e redefinição.
Por exemplo, seu aplicativo precisa se conectar a diversas fontes de dados. E tem uma conexão padrão.
Para se conectar a outra fonte de dados:
- Primeiro, use um gerenciador de contexto para alterar a conexão padrão para uma nova.
- Segundo, trabalhe com a nova conexão
- Terceiro, redefina-o para a conexão padrão assim que terminar de trabalhar com a nova conexão.
Implementando o protocolo gerenciador de contexto Python
O seguinte mostra uma implementação simples da open()
função usando o protocolo do gerenciador de contexto:
class File:
def __init__(self, filename, mode):
self.filename = filename
self.mode = mode
def __enter__(self):
print(f'Opening the file {self.filename}.')
self.__file = open(self.filename, self.mode)
return self.__file
def __exit__(self, exc_type, exc_value, exc_traceback):
print(f'Closing the file {self.filename}.')
if not self.__file.closed:
self.__file.close()
return False
with File('data.txt', 'r') as f:
print(int(next(f)))
Linguagem de código: Python ( python )
Como funciona.
- Primeiro, inicialize o
filename
emode
no__init__()
método. - Segundo, abra o arquivo no
__enter__()
método e retorne o objeto de arquivo. - Terceiro, feche o arquivo se estiver aberto no
__exit__()
método.
Usando o gerenciador de contexto Python para implementar o padrão de início e parada
O seguinte define uma Timer
classe que suporta o protocolo do gerenciador de contexto:
from time import perf_counter
class Timer:
def __init__(self):
self.elapsed = 0
def __enter__(self):
self.start = perf_counter()
return self
def __exit__(self, exc_type, exc_value, exc_traceback):
self.stop = perf_counter()
self.elapsed = self.stop - self.start
return False
Linguagem de código: Python ( python )
Como funciona.
- Primeiro, importe o arquivo
perf_counter
dotime
módulo. - Segundo, inicie o cronômetro no
__enter__()
método - Terceiro, pare o cronômetro no
__exit__()
método e retorne o tempo decorrido.
Agora você pode usar a Timer
classe para medir o tempo necessário para calcular o Fibonacci de 1000, um milhão de vezes:
def fibonacci(n):
f1 = 1
f2 = 1
for i in range(n-1):
f1, f2 = f2, f1 + f2
return f1
with Timer() as timer:
for _ in range(1, 1000000):
fibonacci(1000)
print(timer.elapsed)
Linguagem de código: Python ( python )
Resumo
- Use gerenciadores de contexto Python para definir contextos de tempo de execução ao executar a
with
instrução. - implementar os métodos
__enter__()
e__exit__()
para suportar o protocolo do gerenciador de contexto.