如何在上下文管理器中安全地处理异常 [英] How to safely handle an exception inside a context manager

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

问题描述

我想我已经读到with内的异常不允许正确调用__exit__.如果我在此注释上写错了,请原谅我的无知.

I think I've read that exceptions inside a with do not allow __exit__ to be call correctly. If I am wrong on this note, pardon my ignorance.

所以我这里有一些伪代码,我的目标是使用一个锁上下文,该锁上下文在__enter__上记录开始日期时间并返回锁id,在__exit__上记录结束日期时间并释放锁:

So I have some pseudo code here, my goal is to use a lock context that upon __enter__ logs a start datetime and returns a lock id, and upon __exit__ records an end datetime and releases the lock:

def main():
    raise Exception

with cron.lock() as lockid:
    print('Got lock: %i' % lockid)
    main()

除了安全地存在上下文之外,我还如何引发错误?

How can I still raise errors in addition to existing the context safely?

注意:我故意在此伪代码中引发基本异常,因为我想在发生任何异常(不仅是预期的异常)时安全退出.

注意:替代/标准并发预防方法无关紧要,我想将此知识应用于任何常规上下文管理.我不知道不同的上下文是否有不同的怪癖.

Note: Alternative/standard concurrency prevention methods are irrelevant, I want to apply this knowledge to any general context management. I do not know if different contexts have different quirks.

PS. finally块是否相关?

PS. Is the finally block relevant?

推荐答案

如果上下文管理器被异常破坏,则按常规方式调用__exit__方法 .实际上,传递给__exit__的参数都与处理这种情况有关!来自文档:

The __exit__ method is called as normal if the context manager is broken by an exception. In fact, the parameters passed to __exit__ all have to do with handling this case! From the docs:

object.__exit__(self, exc_type, exc_value, traceback)

退出与此对象相关的运行时上下文.这些参数描述了导致退出上下文的异常.如果上下文无例外地退出,则所有三个参数都将为无".

Exit the runtime context related to this object. The parameters describe the exception that caused the context to be exited. If the context was exited without an exception, all three arguments will be None.

如果提供了异常,并且该方法希望抑制该异常(即防止其传播),则它应返回一个真值.否则,退出此方法后,异常将被正常处理.

If an exception is supplied, and the method wishes to suppress the exception (i.e., prevent it from being propagated), it should return a true value. Otherwise, the exception will be processed normally upon exit from this method.

请注意,__exit__()方法不应引发传入的异常.这是呼叫者的责任.

Note that __exit__() methods should not reraise the passed-in exception; this is the caller’s responsibility.

因此,您可以看到将执行__exit__方法,然后默认情况下,退出上下文管理器后, 将重新引发任何异常.您可以通过创建一个简单的上下文管理器并使用异常将其断开来进行测试:

So you can see that the __exit__ method will be executed and then, by default, any exception will be re-raised after exiting the context manager. You can test this yourself by creating a simple context manager and breaking it with an exception:

DummyContextManager(object):
    def __enter__(self):
        print('Entering...')
    def __exit__(self, exc_type, exc_value, traceback):
        print('Exiting...')  
        # If we returned True here, any exception would be suppressed!

with DummyContextManager() as foo:
    raise Exception()

运行此代码时,您应该看到所需的所有内容(由于print往往会在回溯中间结束,因此可能会出现故障):

When you run this code, you should see everything you want (might be out of order since print tends to end up in the middle of tracebacks):

Entering...
Exiting...
Traceback (most recent call last):
  File "C:\foo.py", line 8, in <module>
    raise Exception()
Exception

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

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