Python 如何在上下文管理器的退出中操作异常?

Python 如何在上下文管理器的退出中操作异常?,python,python-2.x,contextmanager,Python,Python 2.x,Contextmanager,我知道在上下文管理器的\uuuu exit\uuuu()方法中重新引发异常是一种糟糕的方式。因此,我想在实例上添加一个属性,该属性可以携带上下文信息,如果我让异常慢慢通过或捕获它,这些信息是不可用的。这将避免重新提起它 在异常上附加属性的另一种方法是吞下异常,在实例上设置一些状态,该状态兼作所讨论的上下文管理器,然后检查该状态。问题是这会导致第22条军规,不是吗?因为异常意味着退出with块内的执行。除了用再次输入块,没有办法重复该操作,对吗?因此,一旦\uuuu exit\uuuu()方法返回

我知道在上下文管理器的
\uuuu exit\uuuu()
方法中重新引发异常是一种糟糕的方式。因此,我想在实例上添加一个属性,该属性可以携带上下文信息,如果我让异常慢慢通过或捕获它,这些信息是不可用的。这将避免重新提起它

在异常上附加属性的另一种方法是吞下异常,在实例上设置一些状态,该状态兼作所讨论的上下文管理器,然后检查该状态。问题是这会导致第22条军规,不是吗?因为异常意味着退出
with
块内的执行。除了用再次输入
块,没有办法重复该操作,对吗?因此,一旦
\uuuu exit\uuuu()
方法返回,我尝试存储上下文信息的实例就会消失


简而言之:在
\uuuuu exit\uuuuu()
方法中,如何操作挂起的实际异常(如果是,我将假设它是针对这个问题给出的)呢?

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

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

    cm = ContextManager()
    with cm:
        # ....
    
    state = cm.attribute
    
  • \uuu enter\uu
    方法返回上下文管理器本身,使用
    和。。。作为…
    将其绑定到本地名称。当退出
    with
    时,该名称不会解除绑定:

    with ContextManager() as cm:
        # ....
    
    state = cm.attribute
    
    其中
    ContextManager.\uuuu输入\uuuu
    使用
    返回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
    仍然绑定到上下文管理器。

    谁说这是糟糕的风格?上下文管理器是转换异常的一种很好的方法。@MartijnPieters:实际上,文档说明它的样式不好,因为它会给嵌套的上下文管理器带来问题。是的,对于转换和不嵌套,这一点很好。您不应该重新引发相同的异常(仅返回
    None
    可确保保持异常状态),但您可以引发新的异常。@MartijnPieters:的确如此。但例外情况很好,只是我需要在呼叫链上传递一些信息。这就是为什么在我的例子中重新提升是不好的风格。我的假设是你的
    v.extra_属性='foobar'
    和我的
    setattr(exc_值,'extra_属性,'foobar')
    在功能上是等价的。但是,使用它会给出
    AttributeError:“str”对象没有属性“extra\u attribute”
    。为什么我看到的值是
    str
    实例而不是异常实例?它在
    \uuuu exit\uuuu()方法中。是否引发字符串异常?这是非常不赞成的。仅使用对象异常(因此
    BaseException
    的子类)。如果您无法控制引发的异常,则无法对那些属于旧式字符串异常的异常设置属性。标准库当然不再提出这些问题,但我不知道您在这里使用的是什么系统。:-)最后但并非最不重要的一点是,在Python2.6中完全删除了字符串异常支持,因此,如果您在2.6或2.7中看到这一点,则会出现其他错误。你能给我看一个能说明你所看到的问题的要点或贴纸吗?我当然不能在Python2.7中重现与
    setattr()有关的任何问题。@0xC000002L:发现了错误;这是Python 2.6实现的一个问题: