пятница, 8 августа 2008 г.

Оператор with в Python

В прошлом посте я жаловался, что в Python мне не хватает чего-то похожего на C++-ные деструкторы, которые вызываются в любом случае для объекта созданного в стеке при выходе из области видимости, даже когда возникает исключение. В комментария, AQUAGNU упомянул оператор with, который в Python 2.5 был еще на "птичьих правах" (для его использования надо импортировать with_statement из модуля __future__), а в 2.6 стал зарезервированным словом.

Оператор with автоматизирует выполнение операций при входе в блок кода и при выходе из него не зависимо от того, было ли исключении при исполнении блока. Под операциями входа в блок и выхода из блока имеется ввиду, например, открытие и закрытие файла, залочивание и разлочивание при синхронизации. Это можно делать (как я раньше и делал) при помощи try/finally:
with все несколько упрощает:
Объект, который подается на вход with, называется менеджером контекста. У него должен быть реализован протокол менеджера контекста, состоящий из двух методов:
__enter__() - вызывается перед началом выполнения блока (контекста);
__exit__(type, value, traceback) - вызывается по завершению выполнения блока. Параметры, передаваемые ему, описывают исключение, если блок его сгенерировал.

В общем виде это выглядит так (взято отсюда):

В 2.5 версии контекст менеджерами могут выступать файлы, thread.LockType, threading.Lock, threading.RLock, threading.Condition, threading.Semaphore, threading.BoundedSemaphore. Применение with для Lock было показанное во втором примере. Для остальных случаев, прийдется реализовать протокол менеджера контекста или сделать адаптер:

Вот такой вот забавный оператор with.

PS: оказывается with был еще в делфи
PS2: дополнительно можно почитать здесь и здесь.

4 комментария:

Сергей комментирует...

Если без ehandler то вот так еще хорошо: http://pastebin.com/f2187c644

sash_ko комментирует...

2Сергей: хороший пример, спасибо за ссылку

Alno комментирует...

Про with в дельфи:

Он имел несколько другую семантику: просто связывание текущей области видимости с какой-либо переменной.

Т.е. в дельфи:

with a do begin b := 1; call(3); end;

эквивалентно a.b := 1; a.call(3);, если, конечно у a есть соответствующие поля и методы.

sash_ko комментирует...

перечитал еще раз - действительно, в первый раз я не правильно понял :)