2015-01-26 4 views
2

Я думаю, что я читал, что исключения внутри with не позволяют __exit__ правильно звонить. Если я ошибаюсь в этой заметке, прошу простить мое невежество.python, как безопасно обрабатывать исключение внутри диспетчера контекста

Так у меня есть некоторый псевдокод здесь, моя цель состоит в том, чтобы использовать контекст блокировки, что после __enter__ регистрирует стартовый DateTime и возвращает идентификатор блокировки, а на __exit__ записывает конец DateTime и освобождает замок:

def main(): 
    raise Exception 

with cron.lock() as lockid: 
    print('Got lock: %i' % lockid) 
    main() 

Как я могу все еще повышать ошибки в дополнение к существующему контексту?

Примечание: Я намеренно поднимаю базовое исключение в этом псевдокоде, так как я хочу выйти безопасно в любое исключение, а не только ожидаемые исключения.

Примечание: Альтернативные/стандартные методы предотвращения параллелизма не имеют значения, я хочу применить эти знания к любому управлению общим контекстом. Я не знаю, имеют ли разные контексты разные причуды.

PS. Соответствует ли блок finally?

+1

Где вы получаете информацию? Я понимаю, что «с контекстами» * предназначены для * обработки очистки, если происходят какие-либо необработанные исключения. –

+0

@JoelCornett Я думаю, что я получил информацию из SO-страниц, посвященных особенно вложенным контекстам. – ThorSummoner

ответ

9

Метод __exit__называется нормальным, если менеджер контекста разбит на исключение. Фактически, параметры, переданные в __exit__, связаны с обработкой этого случая! От the docs:

object.__exit__(self, exc_type, exc_value, traceback)

Выход из контекста выполнения связанных с этим объектом. Параметры описывают исключение, вызвавшее выход из контекста. Если контекст был исключен без исключения, все три аргумента будут None.

Если предоставляется исключение, и метод хочет исключить исключение (т. Е. Предотвратить его распространение), он должен вернуть истинное значение. В противном случае исключение будет обработано обычно после выхода из этого метода.

Отметьте, что методы __exit__() не должны ререйзировать исключение, это обязанность звонящего.

Таким образом, вы можете видеть, что метод __exit__ будет выполняться, а затем, по умолчанию, любое исключение будет вновь поднят после выхода из менеджера контекста. Вы можете проверить это самостоятельно, создав простой менеджер контекста и разорвать его с исключением:

DummyContextManager(object): 
    def __enter__(self): 
     print('Entering...') 
    def __exit__(self, exc_type, exc_value, traceback): 
     print('Exiting...') 
     # If we returned True here, any exception would be suppressed! 

with DummyContextManager() as foo: 
    raise Exception() 

При запуске этого кода, вы должны увидеть все, что вы хотите (может быть из того, поскольку print стремится оказаться в the middle of tracebacks):

Entering... 
Exiting... 
Traceback (most recent call last): 
    File "C:\foo.py", line 8, in <module> 
    raise Exception() 
Exception