Наткнулся в интернете на интересный пример использования менеджера контекста и оператора 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