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实现的一个问题: