Поскольку вам нужно выходить из диспетчера контекста как во время ошибок, так и не ошибок, я не думаю, что возможно сделать общий сценарий использования с метаклассами или вообще вообще. Для этого вам понадобятся блоки try / finally.
Но, возможно, в вашем случае можно сделать что-то еще. Это зависит от того, для чего вы используете контекстный менеджер.
Использование __del__
может помочь в некоторых случаях, например, освобождение ресурса, но, поскольку вы не можете быть уверены, что он вызывается, его можно использовать только в том случае, если вам нужно освободить ресурсы, которые будут освобождены при выходе из программы. Это также не сработает, если вы обрабатываете исключения в методе __exit__
.
Я предполагаю, что самый чистый метод - это обернуть все управление контекстом в своего рода вызов управления контекстом и извлечь блок кода в метод. Примерно так (непроверенный код, но в основном украденный из PEP 343):
def call_as_context_manager(mgr, function):
exit = mgr.__exit__
value = mgr.__enter__()
exc = True
try:
try:
function(value)
except:
exc = False
if not exit(*sys.exc_info()):
raise
finally:
if exc:
exit(None, None, None)