处理异常的上下文管理器

问题描述 投票:0回答:2

我正在努力解决如何编写一个上下文管理器,该上下文管理器在处理任何异常的同时处理一些日志的问题。我要解决的问题是制作这样的代码:

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

我想我的问题更多是类型:如何确保上下文管理器正确捕获,记录并重新引发正在包装的代码的任何异常?

python contextmanager
2个回答
2
投票

@contextmanager装饰器的工作方式,您应该在上下文管理器函数中编写一次@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:获取异常信息。


2
投票

而不是使用sys.exc_info(),我发现此任务有点笨拙(您需要伪造一个带有yield的生成器以记录异常),而是自己编写一个上下文管理器。它只是一个带有两个特殊方法的类。使用预定义的sys.exc_info(),您只需实现其中之一即可:

contextmanager
© www.soinside.com 2019 - 2024. All rights reserved.