在with语句内部抛出的异常如何捕获

4
zip_file_name = "not_exist.py"

try:
   with zipfile.ZipFile(zip_file_name) as f_handle:
       print("open it successfully")
except (zipfile.BadZipfile, zipfile.LargeZipFile), e:
       print(e)

这是处理由with语句引发异常的正确方式吗?


3
可能是Catching an exception while using a Python 'with' statement的重复问题。 - Cédric Julien
2个回答

5

是的,这就是你想要从with语句内部处理异常的方式。上下文管理器(实现with语句背后的行为)可以处理异常,但只应该这样做以正确清理对象使用的资源。

以下是相关文档中的片段:

如果BLOCK引发异常,则将调用上下文管理器的exit()方法,带有三个参数:异常详细信息(类型、值、回溯,与sys.exc_info()返回的相同值,如果没有发生异常,则也可以为None)。该方法的返回值控制是否重新引发异常:任何假值都会重新引发异常,True将导致抑制异常。您只会很少想要抑制异常,因为如果您这样做,包含“with”语句的代码的作者将永远不会意识到出了什么问题。


1
虽然这是正确的,但这并不是全部。该文档是指来自with语句的BLOCK部分的异常。它*不适用于返回ContextManager的表达式引发的异常。如果您查看OP捕获的异常类型,似乎OP对后者感兴趣。 - Mark Byers

3

好的,没问题。

另一种选择是:

try:
   f_handle = zipfile.ZipFile(zip_file_name)
   # no more code here
except (zipfile.BadZipfile, zipfile.LargeZipFile), e:
   print(e)
else:
   with f_handle:
      print("open it successfully")

这可以防止你在except处理程序中意外捕获with语句体内的异常。


如果在获取资源后发生异常,这将不会给ZipFile清理的机会(ContextManager的__exit__部分)。如果您要走这条路,我建议改用try/except/finally。 - Chris Phillips
@Chris Phillips:嗯...在赋值成功和调用with语句之间可能会发生哪些异常? - Mark Byers
@Mark,我猜Chris做了一个假设,即在赋值语句后面可以添加更多的代码。我已经在你的代码中做了一个注释,并看到它对他起作用了。 - q0987

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接