我知道从上下文管理器的__exit__()
方法中重新引发异常是不好的方式。所以,我想在实例上添加一个属性,该属性可以携带不可用的上下文信息,如果我让异常通过或如果我抓住它。这样可以避免重新提升它。
在异常上添加属性的替代方法是吞下异常,在实例上设置一些状态,该状态兼作相关的上下文管理器,然后检查该状态。问题是,这会导致捕获22,不是吗?由于异常意味着正在退出with
块内的执行。除了再次进入with
区块之外,无法重复操作,对吗?因此,一旦__exit__()
方法返回,我试图存储上下文信息的实例就会消失。
简而言之:在__exit__()
方法中,如何处理待处理的实际异常(如果是,我将假设为此问题的假设)?
答案 0 :(得分:7)
上下文管理器不会因为块退出而消失。您可以通过两种方式保留它:
首先创建上下文管理器,将其分配给变量,然后对该对象使用with
:
cm = ContextManager()
with cm:
# ....
state = cm.attribute
从__enter__
方法返回上下文管理器本身,使用with ... as ...
将其绑定到本地名称。当with
退出时,该名称不会被取消:
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
仍然绑定到上下文管理器。