Уведомления

Группа в Telegram: @pythonsu

#1 Ноя. 10, 2013 15:57:38

plusplus
От:
Зарегистрирован: 2009-01-05
Сообщения: 418
Репутация: +  15  -
Профиль   Отправить e-mail  

Зачем нужен декоратор @contextmanager ?

Не могу понять какой от него толк, если внутри него всё равно необходимо писать try…finally?

import contextlib
@contextlib.contextmanager
def make_context():
    print '  entering'
    try:
        yield {}
    except RuntimeError, err:
        print '  ERROR:', err
    finally:
        print '  exiting'

И наоборот, если не писать:
import contextlib
@contextlib.contextmanager
def make_context(name):
    print 'entering:', name
    yield name
    print 'exiting :', name
with make_context('something'):
     print 'middle'
     raise Exception('something')
то, если сработает исключение, код print ‘exiting’ не выполнится. В чем тогда смысл данной конструкции, зачем она нужна?



Офлайн

#2 Ноя. 10, 2013 16:26:40

Lexander
От:
Зарегистрирован: 2008-09-19
Сообщения: 1139
Репутация: +  33  -
Профиль   Отправить e-mail  

Зачем нужен декоратор @contextmanager ?

Потом пишем:

with make_context(name):
    do_some_work_with_that_name()
и гарантированно печатаем ‘exiting’

Полезно, если внутри make_context выполняется сразу несколько операций, в процессе которых возможны проблемы и нам нужно вернуть все на начало вызова функции.

Например, внутри работа с временными файлами.
Сделал дело и почистил после себя.



Офлайн

#3 Ноя. 10, 2013 17:23:14

plusplus
От:
Зарегистрирован: 2009-01-05
Сообщения: 418
Репутация: +  15  -
Профиль   Отправить e-mail  

Зачем нужен декоратор @contextmanager ?

Lexander
и гарантированно печатаем ‘exiting’

Дак если бы, но не пишет оно, вот код:

import contextlib
@contextlib.contextmanager
def make_context(name):
    print 'entering:', name
    yield name
    print 'exiting :', name
with make_context('something'):
     print 'middle'
     raise Exception('something')

У меня не пишет, ЧЯДНТ?



Отредактировано plusplus (Ноя. 10, 2013 17:23:29)

Офлайн

#4 Ноя. 10, 2013 17:42:52

sergeek
Зарегистрирован: 2012-06-26
Сообщения: 470
Репутация: +  43  -
Профиль   Отправить e-mail  

Зачем нужен декоратор @contextmanager ?

Оно с исключениями никак не связано. Это используют для того чтобы повысить читабельность в случаях когда нужно что-то выполнить перед вступлением и перед выходом из контекста
как тут вон

Отредактировано sergeek (Ноя. 10, 2013 17:47:15)

Офлайн

#5 Ноя. 10, 2013 17:58:13

Lexander
От:
Зарегистрирован: 2008-09-19
Сообщения: 1139
Репутация: +  33  -
Профиль   Отправить e-mail  

Зачем нужен декоратор @contextmanager ?

plusplus
У меня не пишет, ЧЯДНТ?
В этом примере выход идет раньше на строчке с yield и с исключениями это действительно не связано.



Офлайн

#6 Ноя. 10, 2013 18:10:45

Lexander
От:
Зарегистрирован: 2008-09-19
Сообщения: 1139
Репутация: +  33  -
Профиль   Отправить e-mail  

Зачем нужен декоратор @contextmanager ?

Давайте зайдем с другого конца.
Менеджер контекста, создаваемый с помощью with нужен для правильного завершения операций внутри контекста.
Так и с @contextlib.contextmanager.
Использовать его нужно именно в этих случаях, когда нужно гарантировать, чтобы вне зависимости от ошибок или исключений внутри создаваемого контекста, после выхода из контекста состояние программы было предсказуемым.

Пример.

Нужно собрать заархивированные данные последовательно из нескольких источников достаточно большого объема и слить их вместе, обработать и удалить все временные данные.
По одному файлу для каждого источника.

Создаем контекст.
Запускаем внутри функцию, которая сохраняет архивы в temp, там же их распаковывает и сливает в один файл.
Потом этот файл копируем куда нам нужно.
Так как во время процедуры работы с файлами могут возникнуть исключения, то нам нужно гарантировать удаления всех созданных нами временных файлов из temp.
Вот именно этот код удаления мы и поместим в finally созданного с помощью @contextlib.contextmanager контекста.



Офлайн

#7 Ноя. 11, 2013 04:00:03

bw
От:
Зарегистрирован: 2007-09-26
Сообщения: 938
Репутация: +  20  -
Профиль   Адрес электронной почты  

Зачем нужен декоратор @contextmanager ?

Отвечая на первый вопрос: какой толк?
Одна функция с декоратором или класс с двумя методами, есть разница?
В зависимости от задачи я, как использую этот декоратор, так и не ленюсь, пишу класс. Что вообще за вопрос такой. Ну и на всякий случай, мало ли, через `yield` возвращается значение, которое становится доступным в `with`, если определяется переменная после `as`. В `contextmanager` 4 строчки кода, но возможно TC поленился их изучить.
Теперь всё, все покровы сорваны, больше секретов в этой тайной технологии не осталось, ты посвящён в ближний круг :-).

..bw



Офлайн

Board footer

Модераторировать

Powered by DjangoBB

Lo-Fi Version