如何在上下文管理器的 __exit__ 中操作异常? [英] How to manipulate the exception in __exit__ of a context manager?

查看:32
本文介绍了如何在上下文管理器的 __exit__ 中操作异常?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我知道从上下文管理器的 __exit__() 方法中重新引发异常是一种糟糕的风格.因此,我想在实例上添加一个属性,该属性可以携带上下文信息,如果我让异常涓涓细流或捕获它,则该属性将不可用.这将避免重新加注.

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

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

解决方案

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

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

    cm = ContextManager()与厘米:# ....状态 = cm.attribute

  2. __enter__ 方法返回上下文管理器本身,使用 with ... as ... 将其绑定到本地名称.with 退出时,该名称未绑定:

     使用 ContextManager() 作为 cm:# ....状态 = cm.attribute

    其中 ContextManager.__enter__ 使用 return self.

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

<预><代码>>>>类上下文管理器(对象):... def __enter__(self):... 回归自我... def __exit__(self, tp, v, tb):...如果 tp 为 None:返回... v.extra_attribute = 'foobar'... self.other_extra_attribute = 'spam-n-ham'...>>>尝试:...与 ContextManager() 作为厘米:... 引发 ValueError('barfoo')... 除了 ValueError 如:... 打印变量(例如)...{'extra_attribute': 'foobar'}>>>变量(厘米){'other_extra_attribute': '垃圾邮件'}

这里异常被赋予了一个额外的属性,该属性一直持续到异常处理程序.在上面我还表明 cm 仍然绑定到上下文管理器.

I know it's bad style to re-raise an exception from within a context manager's __exit__() method. So, I'd like to tack an attribute on the instance which can carry contextual information that isn't available if I let the exception trickle through or if I catch it. This will avoid re-raising it.

The alternative to tacking the attribute on the exception would be to swallow the exception, set some state on the instance that doubles as the context manager in question and later check that state. Problem is that this would lead to a catch 22, wouldn't it? Since the exception means that execution inside the with block is being exited. There is no way to repeat the operation other than entering the with block again, right? So the instance in which I am trying to store the contextual information would go away once the __exit__() method returns.

So in short: how can I manipulate the actual exception that is pending (if it is, which I'll assume as given for this question) while in the __exit__() method?

解决方案

The context manager doesn't go away just because the block exits. You can preserve it in two ways:

  1. Create the context manager first, assign it to a variable, then use with with that object:

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

  2. Return the context manager itself from the __enter__ method, use with ... as ... to bind that to a local name. That name is not unbound when with exits:

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

    where ContextManager.__enter__ uses return self.

You can also set extra attributes on the exception itself; no need to re-raise the exception:

>>> 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'}

Here the exception was given an extra attribute that persisted all the way to the exception handler. In the above I also show that cm is still bound to the context manager.

这篇关于如何在上下文管理器的 __exit__ 中操作异常?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆