Я вважаю, що на це вже відповіли інші користувачі, тому я додаю це лише для повноти: 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.