Только что прочитал у Pythy, что вышел Python 2.5. В нем много всего нового и змечательного, и что приятно, я даже не нашел на первый взгляд ничего, что вызвало бы отрицательную реакцию.
Но я больше всего рад появлению одной конкретной вещи -- оператора with.
with в DelphiЯ очень любил оператор with, когда активно писал на Delphi, даже несмотря на опасность попутать переменные из разных областей видимости. Во-первых, потому что удобство от неписания постоянно одного и то же имени переменной у меня перекрывало редкие случаи багов, но главное, потому что он обладает очень четкой узнаваемой семантикой: локальный блок операций надо одним главенствующим объектом.
Из этой семантики естественным образом вытекает то, что with удачно сочетается с блоком try..finally, который гарантирует правильное создание и уничтожение объекта:
With TFileStream.Create(FileName) Do
Try
{ ... }
Finally
Free;
End;
И можно обойтись без объявления переменной.
Я, кстати, именно так без отступа писал try..finally, чтобы подчеркнуть, что эта конструкция составляет с with одно логическое целое.
with в ПитонеИ вот именно потому мне так и нравится новый питоновский with, что он реализует как раз такое поведение: не просто блок с "главным" объектом, но еще и с автоматической его инициализацией и гарантированным завершением. То есть вся эта катавасия с громоздким try..finally сведена в короткую синтаксическую конструкцию:
with open(filename) as f: # файл открывается
f.read(100)
# файл закрывается, даже после exception'ов
или
with threading.Lock():
# код критической секции
# lock освободится после выхода из with
Определение того, что именно происходит при инициализации и завершении, сделано чисто по-питоновски: методами __enter__() и __exit__() объекта, который стоит под with. То есть можно легко делать и свои объекты, которые будут способны создать такой блок (который теперь называется контекстом, а объекты, соответственно, менеджерами контекста).
И что еще приятно! Той самой опасной особенности паскалевского with в Питоне как раз и нет :-). Переменную, которая представляет объект в контексте, нужно указывать явно.
try..finallyЕще одна штука, которой сильно не хватало в Delphi -- это красивая синтаксическая возможность управлять уничтожением нескольких объектов.
Простой пример -- блок кода, который работает с двумя файлами. Если написать так:
InFile := TFileStream.Create('...', fmOpenRead);
OutFile := TFileStream.Create('...', fmOpenWrite);
Try
{ процесс }
Finally
InFile.Free;
OutFile.Free;
End;
... то это, вообще-то, будет некорректно: при ошибке на второй строчке, которая идет до try, finally никогда не выполнится, и первый файл останется открытым. Поэтому более корректным будут два вложенных блока:
InFile := TFileStream.Create('...', fmOpenRead);
Try
OutFile := TFileStream.Create('...', fmOpenWrite);
Try
{ процесс }
Finally
OutFile.Free;
End;
Finally
InFile.Free;
End;
Но это уже дикость нечитаемая :-(.
В Питоне 2.5 для оформления таких вещей появилась библиотечная функция:
from contextlib import nested
with nested(open('...', 'r'), open('...', 'w')) as (in_file, out_file):
# процесс
# по выходу гарантирует закрытие и одного, и другого файлов
Ну и еще там есть всякие полезные утилитки, которые упрощают создание своих менеджеров контектса, используя распространенные паттерны и соглашения языка (как например то, что у подавляющего большинства объектов, которые можно "закрыть", этот метод называется close() и никак иначе).
Эх... Приятно все-таки работать с языком, который так хорошо ложится на мозги!
Комментарии: 11
CR
20.09.06 14:06
Одно не могу понять: зачем вводить слова
__enter__()и__exit__(), когда достаточно обойтись del'ом ?Иван Сагалаев
20.09.06 14:27
Мне видятся сразу несколько причин.
Эта пара методов позволяет не привязывать время жизни объекта к
with. Например, если есть какой-то большой и сложный объект, который живет в программе от начала и до конца, но который в том числе может работать временами и как менеджер контекста.Вызов
__del__не гарантируется при выходе изwith, он вызовется когда-нибудь потом, когда будет удобно garbage collector'у. А закрывать файл или освобождать lock как раз и нужно обычно делать сразу и надежно.В
__exit__передаются еще и параметры возникшего exception'а, если оно есть, чтобы его можно было обработать.Шаген Оганджанян
23.09.06 13:37
А мне очень понравилась конструкция
x = true_value if condition else false_value
Vestel » Blog Archive » Python again
29.09.06 20:56
[...] Ruby конечно хорош. Тут язык у меня ничего против сказать не повернется. Но жена его не знает, зато на первом курсе слушала краткое введение в Python. Понятное дело, его и выбрала в качестве языка для курсовой работы. Я соответственно, как защитник и помошник, пользуясь получасовым затишьем любезно предоставленным дочкой Анечкой, решил подчитать что интересного в мире удава произошло с тех пор, как я последний раз интересовался им. Оказывается вышла новая версия, которая несет некоторые очень толковые изменения, в частности with и nested. Подробнее о with в python-e пишет в своем блоге Иван Сагалаев, куда я и рекоммендую глянуть всем заинтересовавшимся. [...]
declonter
5.02.07 21:57
А почему бы не так:
?
Иван Сагалаев
5.02.07 22:02
Наверное имелся в виду Free вместо Close, но смысл понятен.
InFile и OutFile до начала этого блока содержат мусор. Поэтому если подорвется создание InFile, то OutFile так и не будет инициализирован, и OutFile.Free вероятнее всего вызовет access violation. А писать
до начала тоже не особенно приятно.
Иван Сагалаев
5.02.07 22:03
Ой... А я и в статье везде Close вместо Free понаписал :-). Все позабыл напрочь :-). Пошел исправлять...
declonter
5.02.07 23:41
Иван Сагалаев, да, действительно access violation. А Close был получен методом copy-paste :)
DemonZLa
30.03.07 19:14
По мне так лучше access violation... чем допустить работать проге тогда когда файл не открыт и следовательно вся дальнейшая логика проги идёт к чертям собачьим...
Murkt’s codehole » Забытые возможности Python
7.07.07 16:11
[...] Python, как генераторы, декораторы, list comprehensions, оператор with… Но есть в Питоне и некоторые возможности, которые [...]
Amazon byteflow: Забытые возможности Python
8.12.07 11:45
[...] Python, как генераторы, декораторы, list comprehensions, оператор with… Но есть в Питоне и некоторые возможности, которые [...]