处理异常的上下文管理器
Context Manager that handles exceptions
我正在努力思考如何编写一个上下文管理器来处理在处理任何异常时写入一些日志。我要解决的问题是编写如下代码:
try:
# code that can raise exception here
except Exception as e:
print('failed', e)
print('all good')
这是我在代码中重复的模式,我认为最好使用上下文管理器来处理它,例如:
with my_ctx_manager(success_msg='all good', failed_msg='failed):
# code that can raise exception here
这看起来好多了,但我不知道如何编写实际的上下文管理器来处理上下文中可能出现的任何异常。
@contextlib.contextmanager
def my_ctx_manager(success_msg, failed_msg):
try:
# if no exception then print(success_msg)
# How do I catch any exception here
except Exception:
print(failed_msg)
# I need the exception to propagate as well
raise
我想我的问题更多的是:如何确保上下文管理器正确捕获、记录并重新引发包装代码的任何异常?
@contextmanager
装饰器的工作方式,你应该在上下文管理器函数中写一次 yield
,这样 with
块将在 yield
语句暂停函数的执行。这意味着如果 with
块抛出异常,您可以通过将 yield
包装在 try
/except
块中来捕获它:
from contextlib import contextmanager
@contextmanager
def example():
print('entered the context manager')
managed_resource = 'some resource'
try:
yield managed_resource
except Exception as e:
print('caught:', e)
# any cleanup that should only be done on failure
raise
else:
# any cleanup that should only be done on success
print('no exception was thrown')
finally:
# any cleanup that should always be done
print('exited the context manager')
with example() as resource:
print('resource:', resource)
raise ValueError('some error message')
输出:
entered the context manager
resource: some resource
caught: some error message
exited the context manager
Traceback (most recent call last):
File "<stdin>", line 3, in <module>
ValueError: some error message
如果你想捕获所有的东西(不仅仅是Exception
),那么你可以写一个空的except:
块并使用sys.exc_info()
来获取异常信息。
与其使用 contextmanager
,我发现它对于这个任务来说有点笨拙(你需要伪造一个带有 yield 的生成器来记录异常),而是自己编写一个上下文管理器。它只是一个带有两个特殊方法的 class。使用预定义的 AbstractContextManager
你只需要实现其中之一:
import contextlib
class ExceptionLogger(contextlib.AbstractContextManager):
def __exit__(self, exc_type, exc_value, traceback):
if exc_type:
print("***Logging exception {}***".format((exc_type, exc_value,
traceback)))
with ExceptionLogger():
raise ValueError("foo")
我正在努力思考如何编写一个上下文管理器来处理在处理任何异常时写入一些日志。我要解决的问题是编写如下代码:
try:
# code that can raise exception here
except Exception as e:
print('failed', e)
print('all good')
这是我在代码中重复的模式,我认为最好使用上下文管理器来处理它,例如:
with my_ctx_manager(success_msg='all good', failed_msg='failed):
# code that can raise exception here
这看起来好多了,但我不知道如何编写实际的上下文管理器来处理上下文中可能出现的任何异常。
@contextlib.contextmanager
def my_ctx_manager(success_msg, failed_msg):
try:
# if no exception then print(success_msg)
# How do I catch any exception here
except Exception:
print(failed_msg)
# I need the exception to propagate as well
raise
我想我的问题更多的是:如何确保上下文管理器正确捕获、记录并重新引发包装代码的任何异常?
@contextmanager
装饰器的工作方式,你应该在上下文管理器函数中写一次 yield
,这样 with
块将在 yield
语句暂停函数的执行。这意味着如果 with
块抛出异常,您可以通过将 yield
包装在 try
/except
块中来捕获它:
from contextlib import contextmanager
@contextmanager
def example():
print('entered the context manager')
managed_resource = 'some resource'
try:
yield managed_resource
except Exception as e:
print('caught:', e)
# any cleanup that should only be done on failure
raise
else:
# any cleanup that should only be done on success
print('no exception was thrown')
finally:
# any cleanup that should always be done
print('exited the context manager')
with example() as resource:
print('resource:', resource)
raise ValueError('some error message')
输出:
entered the context manager
resource: some resource
caught: some error message
exited the context manager
Traceback (most recent call last):
File "<stdin>", line 3, in <module>
ValueError: some error message
如果你想捕获所有的东西(不仅仅是Exception
),那么你可以写一个空的except:
块并使用sys.exc_info()
来获取异常信息。
与其使用 contextmanager
,我发现它对于这个任务来说有点笨拙(你需要伪造一个带有 yield 的生成器来记录异常),而是自己编写一个上下文管理器。它只是一个带有两个特殊方法的 class。使用预定义的 AbstractContextManager
你只需要实现其中之一:
import contextlib
class ExceptionLogger(contextlib.AbstractContextManager):
def __exit__(self, exc_type, exc_value, traceback):
if exc_type:
print("***Logging exception {}***".format((exc_type, exc_value,
traceback)))
with ExceptionLogger():
raise ValueError("foo")