Acredito que isso já tenha sido respondido por outros usuários antes de mim, portanto, apenas o adiciono por questões de integridade: a with
instrução simplifica o tratamento de exceções, encapsulando tarefas comuns de preparação e limpeza nos chamados gerenciadores de contexto . Mais detalhes podem ser encontrados no PEP 343 . Por exemplo, a open
instrução é um gerenciador de contexto em si, que permite abrir um arquivo, mantê-lo aberto enquanto a execução estiver no contexto da with
instrução em que você o usou e fechá-lo assim que sair do contexto, não importa se você o deixou devido a uma exceção ou durante o fluxo de controle regular. A with
instrução pode, portanto, ser usada de maneiras semelhantes ao padrão RAII em C ++: algum recurso é adquirido pelowith
e liberada quando você sai do with
contexto.
Alguns exemplos são: abrir arquivos usando with open(filename) as fp:
, adquirindo bloqueios usando with lock:
(onde lock
é uma instância de threading.Lock
). Você também pode construir seus próprios gerenciadores de contexto usando o contextmanager
decorador de contextlib
. Por exemplo, costumo usar isso quando preciso alterar temporariamente o diretório atual e depois retornar para onde estava:
from contextlib import contextmanager
import os
@contextmanager
def working_directory(path):
current_dir = os.getcwd()
os.chdir(path)
try:
yield
finally:
os.chdir(current_dir)
with working_directory("data/stuff"):
# do something within data/stuff
# here I am back again in the original working directory
Aqui está outro exemplo que redireciona temporariamente sys.stdin
, sys.stdout
e sys.stderr
para algum outro identificador de arquivo e restaura-los mais tarde:
from contextlib import contextmanager
import sys
@contextmanager
def redirected(**kwds):
stream_names = ["stdin", "stdout", "stderr"]
old_streams = {}
try:
for sname in stream_names:
stream = kwds.get(sname, None)
if stream is not None and stream != getattr(sys, sname):
old_streams[sname] = getattr(sys, sname)
setattr(sys, sname, stream)
yield
finally:
for sname, stream in old_streams.iteritems():
setattr(sys, sname, stream)
with redirected(stdout=open("/tmp/log.txt", "w")):
# these print statements will go to /tmp/log.txt
print "Test entry 1"
print "Test entry 2"
# back to the normal stdout
print "Back to normal stdout again"
E, finalmente, outro exemplo que cria uma pasta temporária e a limpa ao sair do contexto:
from tempfile import mkdtemp
from shutil import rmtree
@contextmanager
def temporary_dir(*args, **kwds):
name = mkdtemp(*args, **kwds)
try:
yield name
finally:
shutil.rmtree(name)
with temporary_dir() as dirname:
# do whatever you want
with
na documentação do Python 3.