python - 为什么 try-except-else 中的 else 内部的异常不会重新抛出?
问题描述
我正在使用try
| except
| else
| finally
在蟒蛇。如果里面的代码else
抛出异常,我希望我的整个脚本失败(在执行之后finally
)。我发现这没有发生。内部的异常else
被抑制。为什么?
MWE
import requests
def foo():
try:
resp = requests.get("https://example.com")
status = resp.status_code
assert resp.status_code < 300, "Bad status code"
except requests.exceptions.BaseHTTPError:
status = None
else:
print("Starting else branch")
# this should fail
# because the body is not json
print(f"Response body was {resp.json()}")
print("Finishing else branch")
finally:
# save the result persistently,
# regardless of if it was good or bad
with open('log.txt', 'w') as f:
f.write(str(status))
return status
print(f"foo() gracefully returned {foo()}")
我在 python 3.6.9、3.9.5 和 3.8 中尝试过。
期望的行为:
resp.json()
在 内部抛出simplejson.errors.JSONDecodeError
异常else
,然后被捕获,finally
运行,但随后重新抛出异常else
,因此整个脚本失败并带有.JSONDecodeError
stdout
显示:
开始其他分支
然后抛出异常,并回溯到resp.json()
.
else
in try
|的python 文档 except
| else
| finally
说:
使用 else 子句比在 try 子句中添加额外的代码要好,因为它可以避免意外捕获不是由 try ... except 语句保护的代码引发的异常。
因此,听起来该else
子句的目的是将代码放在您不希望捕获异常的地方。这就是我想要的。但似乎else
正在捕获异常。
(请注意,在这个例子中,我希望 AssertionError 导致整个函数失败,并且 BaseHTTPError 被捕获并优雅地处理。这对于实际用例来说没有意义,但这只是一个简单的 MWE。)
实际行为
stdout
说:
开始其他分支
foo() 优雅地返回 200
内部的JSONDecodeError
异常else
被捕获,finally
被执行,代码返回200
。也就是说,else
代码中的异常被捕获了。else
因此,分支中的代码似乎受try
.
如果我想JSONDecodeError
为我的.json()
线路被抓住,我会把它放在try
. 如何使此脚本不捕获JSONDecodeError
错误?
解决方案
您所看到的已完全记录在案:
如果
finally
存在,它指定一个“清理”处理程序。该try
子句被执行,包括任何except
和else
子句。如果任一子句发生异常且未处理,则暂时保存该异常。finally
子句被执行。finally
如果存在已保存的异常,则会在子句末尾重新引发。如果finally
子句引发另一个异常,则将保存的异常设置为新异常的上下文。如果finally
子句执行return
,break
orcontinue
语句,则丢弃保存的异常:>>> def f(): ... try: ... 1/0 ... finally: ... return 42 ... >>> f() 42
要在执行else
后引发内部异常finally
,您不能有return
inside finally
。取消缩进以将其移出finally
分支。
推荐阅读
- android - 为 Google Play 多人游戏创建不同的房间
- google-cloud-platform - 子文件夹的 GCS 对象更改通知
- python - 是否有可能获得 Spacy 命名实体识别的置信度分数
- angular - 我应该使用 null 作为数字的值吗 - Angular
- node.js - 如何在nodejs中promise类型的函数中完成.map函数后返回对象
- php - 调用Factory时Laravel记录被删除
- ios - 在主对象选择之前隐藏底部标签栏
- react-native - 路由“x”的组件必须是 React 组件
- reactjs - 在尝试部署到 heroku 时找不到文件(在本地工作)
- javascript - 用于 iOS 构建的多个 Unity 场景脚本