简体   繁体   English

为什么在 except 块中发生异常时,finally 块不返回最新的异常?

[英]Why doesn't finally block return the latest exception when an exception occurs within an except block?

I had written a piece of code where I'm using traceback to return the exception stacktrace.我写了一段代码,我使用回溯来返回异常堆栈跟踪。 But I forgot to import traceback.但是我忘了导入回溯。

Filename - trial_main.py文件名 - trial_main.py

from fastapi import FastAPI
from pydantic import BaseModel
import uvicorn


app = FastAPI()

class RequestJson(BaseModel):
    data: str


@app.post("/trial", status_code=200)
async def trial(req:RequestJson):
    try:
        status = "default"
        resp = {
            "status": status,
            "reason": "default reason"
        }
        
        # error point
        a = 10/0
        
        status = "complete"
        reason = "Finished converting from base64 to image"
        
        resp = {
            "status": status,
            "reason": reason
        }
    except Exception as e:
        status = "incomplete"
        resp =  {
            "status": status,
            "reason": traceback.format_exc(),
        }
    finally:
        return resp


if __name__ == '__main__':
    uvicorn.run("trial_main:app", host="0.0.0.0", port=5001, log_level="info")

What's confusing me is why isn't the code exiting with an exception since traceback module is not found.令我困惑的是,由于找不到回溯模块,为什么代码没有以异常退出。 Rather it returns the default response that was set earlier.而是返回之前设置的默认响应。

This is the API response that I'm getting -这是我得到的 API 响应 -

{
    "status": "default",
    "reason": "default reason"
}

And this is the output on the terminal where I run the uvicorn server -这是我运行 uvicorn 服务器的终端上的 output -

INFO:     Started server process [14744]
INFO:     Waiting for application startup.
INFO:     Application startup complete.
INFO:     Uvicorn running on http://0.0.0.0:5001 (Press CTRL+C to quit)
INFO:     127.0.0.1:61809 - "POST /trial HTTP/1.1" 200 OK

Api endpoint - Api 端点 -

[POST] http://127.0.0.1:5001/trial

Input to re-create the situation -输入重新创建情况 -

{"data": "randomString"}

No mystery is happens here.这里没有发生任何神秘事件。

In the try block, you successfully assign value to resp variable, then Exception is raised and execution goes to except block.在 try 块中,您成功地为resp变量赋值,然后引发异常并执行到 except 块。 There you're trying to assign new value to resp , but ImportError happens in the right part of statement, so resp still contains old value, which would returned in the finally block.您正在尝试为resp分配新值,但 ImportError 发生在语句的右侧,因此resp仍然包含旧值,该值将在 finally 块中返回。 Exception is not propagated further because there is return in the finally block, it's just suppress exception.异常不会进一步传播,因为 finally 块中有return ,它只是抑制异常。

To not get distracted by fastapi boilerplate all of this could be illustrated with more simple example为了不被 fastapi 样板分散注意力,所有这些都可以用更简单的例子来说明

def always_return():
    """return 1"""
    try:
        res = 1
        raise Exception()
    except Exception:
        res = 1 / 0
    finally:
        return res


def never_return():
    """raises ZeroDivisionError"""

    try:
        res = 1
        raise Exception()
    except Exception:
        res = 1 / 0
    finally:
        print("finally block exists, but no return here")
    return res
>>> print(always_return())
1
>>> print(never_return())
finally block exists, but no return here
ZeroDivisionError: division by zero... traceback

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM