Я считаю, что на это уже отвечали другие пользователи до меня, поэтому я добавляю его только для полноты картины: это with
утверждение упрощает обработку исключений, инкапсулируя общие задачи подготовки и очистки в так называемых контекстных менеджерах . Более подробную информацию можно найти в PEP 343 . Например, open
оператор сам по себе является менеджером контекста, который позволяет открывать файл, сохранять его открытым, пока выполнение находится в контексте with
оператора, в котором вы его использовали, и закрывать его, как только вы выходите из контекста, не важно, оставили ли вы его из-за исключения или во время регулярного потока управления. Таким образом, with
оператор может использоваться способами, подобными шаблону RAII в C ++: некоторый ресурс получаетсяwith
заявление и выпущен, когда вы выходите из with
контекста.
Вот некоторые примеры: открытие файлов с использованием with open(filename) as fp:
, получение блокировок с использованием with lock:
(где lock
это экземпляр threading.Lock
). Вы также можете создавать свои собственные контекстные менеджеры, используя contextmanager
декоратор из contextlib
. Например, я часто использую это, когда мне нужно временно изменить текущий каталог, а затем вернуться туда, где я был:
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
Вот еще один пример , который временно перенаправляет sys.stdin
, sys.stdout
и sys.stderr
в какой - то другой дескрипторе файла и восстанавливают их позже:
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"
И, наконец, еще один пример, который создает временную папку и очищает ее при выходе из контекста:
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
в документации по Python 3.