如何操纵上下文管理器的__exit__中的异常?

时间:2014-11-13 10:53:03

标签: python python-2.x contextmanager

我知道从上下文管理器的__exit__()方法中重新引发异常是不好的方式。所以,我想在实例上添加一个属性,该属性可以携带不可用的上下文信息,如果我让异常通过或如果我抓住它。这样可以避免重新提升它。

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

简而言之:在__exit__()方法中,如何处理待处理的实际异常(如果是,我将假设为此问题的假设)?

1 个答案:

答案 0 :(得分:7)

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

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

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

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

    其中ContextManager.__enter__使用return self

  3. 您还可以在异常本身上设置额外的属性;无需重新提出异常:

    >>> 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仍然绑定到上下文管理器。

相关问题