python - 如何操作上下文管理器的 __exit__ 中的异常?

标签 python python-2.x contextmanager

我知道从上下文管理器的 __exit__() 方法中重新引发异常是不好的风格。因此,我想在实例上附加一个属性,该属性可以携带上下文信息,如果我让异常通过或捕获它,则该信息不可用。这将避免重新提高它。

在异常上附加属性的替代方法是吞下异常,在兼作相关上下文管理器的实例上设置一些状态,然后检查该状态。问题是这会导致陷阱 22,不是吗?因为异常意味着正在退出 with block 内的执行。除了再次进入with block 之外,没有办法重复操作,对吧?因此,一旦 __exit__() 方法返回,我尝试存储上下文信息的实例就会消失。

简而言之:在 __exit__() 方法中,我如何操作挂起的实际异常(如果是,我将假定为这个问题给出的异常)?

最佳答案

上下文管理器不会因为 block 退出而消失。您可以通过两种方式保存它:

  1. 首先创建上下文管理器,将其分配给一个变量,然后对该对象使用 with:

    cm = ContextManager()
    with cm:
        # ....
    
    state = cm.attribute
    
  2. __enter__ 方法返回上下文管理器本身,使用 with ... as ... 将其绑定(bind)到本地名称。当 with 退出时,该名称未解除绑定(bind):

    with ContextManager() as cm:
        # ....
    
    state = cm.attribute
    

    其中 ContextManager.__enter__ 使用 return self

您还可以在异常本身上设置额外的属性;无需重新引发异常:

>>> class ContextManager(object):
...     def __enter__(self):
...         return self
...     def __exit__(self, tp, v, tb):
...         if tp is None: return
...         v.extra_attribute = 'foobar'
...         self.other_extra_attribute = 'spam-n-ham'
... 
>>> try:
...     with ContextManager() as cm:
...         raise ValueError('barfoo')
... except ValueError as ex:
...     print vars(ex)
... 
{'extra_attribute': 'foobar'}
>>> vars(cm)
{'other_extra_attribute': 'spam-n-ham'}

这里为异常赋予了一个额外的属性,该属性一直存在到异常处理程序中。在上面,我还表明 cm 仍然绑定(bind)到上下文管理器。

关于python - 如何操作上下文管理器的 __exit__ 中的异常?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26907175/

相关文章:

python - 我应该如何在 Python 中捕获 `with open(filename)` 引发的异常?

python - Python 内置对象的 __enter__() 和 __exit__() 定义在哪里?

python - 如何从模块中只加载一个类?

python - 为什么这个 hmac 摘要在 Python 2.7 和 Python 3.7 上不同?

python - 如何创建一个 tkinter 切换按钮?

python - 相当于 Win32::Process::Memory 的 python 进程内存搜索

python - 打开文件并在一行中对该文件执行操作是否会关闭该文件?

python - Pandas 日期时间格式不一致

python - tkinter 中的 SQL 查询结果

python - 在运行时切换 TG2 中的数据库