Наткнулся в интернете на интересный пример использования менеджера контекста и оператора with, но перед тем как я покажу что мне понравилось немного матчасти.
Менеджер контекста представляет собой объект, который создает контекст выполнения внутри оператора with и обладает двумя методами _enter_ и _exit_.
Простой пример использования менеджера контекста и оператора with:
class Logger(object):
def __init__(self, val):
self.val = val
print "%d :: __init__" % self.val
def __enter__(self):
print "%d :: __enter__" % self.val
def __exit__(self, exc_type, exc_val, exc_tb):
print "%d :: __exit__ " % self.val
for i in xrange(5):
with Logger(i) as log:
pass
Истинное предназначения оператора with это замена подхода setup..try..except..finally:
do_init()
try :
do_task()
except SomeError :
do_exception_handling()
finally :
do_exit()
Т.е. мы сначала инициализируем наш ресурс (метод _init_ объект менеджера контекста), потом выполняем попытку работы с нашим ресурсом в блоке try..except..finally (внутренний блок оператора with). Если возник ексепшен то попадаем в ветку except и обрабатываем ошибку (метод _exit_ менеджера контекста). По-окончанию выполняется ветка finally (метод _exit_ менеджера контекста) где производим зачистку и освобождение нашего ресурса.
Добавим обработчик ексепшенов в приведенный выше пример работы с менеджером контекста:
class Logger(object):
def __init__(self, val):
self.val = val
print "%d :: __init__" % self.val
def __enter__(self):
print "%d :: __enter__" % self.val
def __exit__(self, exc_type, exc_val, exc_tb):
print "%d :: __exit__ " % self.val
if exc_type:
print "%d !! error " % self.val
return True
for i in xrange(3):
with Logger(i) as log:
if i == 1:
raise ValueError(i)
Получим такой вывод:
0 :: __init__ 0 :: __enter__ 0 :: __exit__ 1 :: __init__ 1 :: __enter__ 1 :: __exit__ 1 !! error 2 :: __init__ 2 :: __enter__ 2 :: __exit__
Это было беглое введение в менеджер контекста, более подробно можно ознакомится на docs.python.org или у sykora.
А теперь пример кода который мне понравился. Этот код показывает как можно начать работать с несколькими файлами используя менеджер контекст и одновременно с этим подчеркивает всю элегантность и наглядность кода на python, за что мы его и любим :). Причем мы можем не переживать за закрытие файлов и освобождение ресурсов (это уже реализовано внутри метода __exi\t__ класса mfw), просто передаем имя файлов и режим работы с ним.
class mfw:
"""
mfw : Multi-File With
This utility class is a list of file handles. It implements __enter__
and __exit__ methods so that it can be used via the with clause.
"""
def __init__(self, *args):
self.handles = []
for (the_file, mode) in args:
self.handles.append(open(the_file, mode))
def __enter__(self):
return self.handles
def __exit__(self, type, value, traceback):
for handle in self.handles:
handle.close()
with mfw(('f1.txt', 'r'), ('f2.txt', 'w')) as (infile, outfile):
print infile.name
print outfile.name