FastAPI教程 與yield的依賴(lài)關(guān)系

2021-11-03 09:37 更新

FastAPI 支持在完成后執(zhí)行一些額外步驟的依賴(lài)項(xiàng)。

為此,請(qǐng)使用yield代替return,并在之后編寫(xiě)額外的步驟。

提示

確保使用yield一次。

技術(shù)細(xì)節(jié)

任何可用于以下功能的有效函數(shù):

用作FastAPI依賴(lài)項(xiàng)是有效的。

事實(shí)上,F(xiàn)astAPI 在內(nèi)部使用了這兩個(gè)裝飾器。

數(shù)據(jù)庫(kù)依賴(lài)項(xiàng) yield

例如,您可以使用它來(lái)創(chuàng)建數(shù)據(jù)庫(kù)會(huì)話并在完成后關(guān)閉它。

yield在發(fā)送響應(yīng)之前,只執(zhí)行包含該語(yǔ)句之前的代碼:

async def get_db():
    db = DBSession()
    try:
        yield db
    finally:
        db.close()

產(chǎn)生的值是注入到路徑操作和其他依賴(lài)項(xiàng)中的值:

async def get_db():
    db = DBSession()
    try:
        yield db
    finally:
        db.close()

yield響應(yīng)傳遞后執(zhí)行語(yǔ)句后面的代碼:

async def get_db():
    db = DBSession()
    try:
        yield db
    finally:
        db.close()

提示

您可以使用async或 正常功能。

FastAPI會(huì)對(duì)每個(gè)都做正確的事情,就像普通的依賴(lài)一樣。

依賴(lài)yield和try

如果您try在依賴(lài)項(xiàng)中使用塊 with yield,您將收到使用該依賴(lài)項(xiàng)時(shí)拋出的任何異常。

例如,如果某些代碼在中間、另一個(gè)依賴(lài)項(xiàng)或路徑操作中的某個(gè)點(diǎn)使數(shù)據(jù)庫(kù)事務(wù)“回滾”或創(chuàng)建任何其他錯(cuò)誤,您將在依賴(lài)項(xiàng)中收到異常。

因此,您可以使用except SomeException.

同樣,您可以使用finally來(lái)確保執(zhí)行退出步驟,無(wú)論是否有異常。

async def get_db():
    db = DBSession()
    try:
        yield db
    finally:
        db.close()

子依賴(lài)項(xiàng) yield

您可以擁有任何大小和形狀的子依賴(lài)項(xiàng)和子依賴(lài)項(xiàng)的“樹(shù)”,并且它們中的任何一個(gè)或全部都可以使用yield.

FastAPI將確保每個(gè)依賴(lài)項(xiàng)中的“退出代碼”以yield正確的順序運(yùn)行。

例如,dependency_c可以對(duì)一個(gè)依賴(lài)dependency_b,并dependency_b于dependency_a:

from fastapi import Depends


async def dependency_a():
    dep_a = generate_dep_a()
    try:
        yield dep_a
    finally:
        dep_a.close()


async def dependency_b(dep_a=Depends(dependency_a)):
    dep_b = generate_dep_b()
    try:
        yield dep_b
    finally:
        dep_b.close(dep_a)


async def dependency_c(dep_b=Depends(dependency_b)):
    dep_c = generate_dep_c()
    try:
        yield dep_c
    finally:
        dep_c.close(dep_b)

所有這些都可以使用yield.

在這種情況下dependency_c,要執(zhí)行其退出代碼,需要來(lái)自dependency_b(此處命名為dep_b)的值仍然可用。

并且,反過(guò)來(lái),dependency_b需要來(lái)自dependency_a(此處命名為dep_a)的值可用于其退出代碼。

from fastapi import Depends


async def dependency_a():
    dep_a = generate_dep_a()
    try:
        yield dep_a
    finally:
        dep_a.close()


async def dependency_b(dep_a=Depends(dependency_a)):
    dep_b = generate_dep_b()
    try:
        yield dep_b
    finally:
        dep_b.close(dep_a)


async def dependency_c(dep_b=Depends(dependency_b)):
    dep_c = generate_dep_c()
    try:
        yield dep_c
    finally:
        dep_c.close(dep_b)

同樣,你可以有依賴(lài)yield和return混合。

并且您可能有一個(gè)依賴(lài)項(xiàng),它需要其他幾個(gè)依賴(lài)項(xiàng)yield,等等。

您可以擁有所需的任何依賴(lài)項(xiàng)組合。

FastAPI將確保一切以正確的順序運(yùn)行。

技術(shù)細(xì)節(jié)

這要?dú)w功于 Python 的Context Managers

FastAPI在內(nèi)部使用它們來(lái)實(shí)現(xiàn)這一點(diǎn)。

與yield和的依賴(lài)關(guān)系HTTPException

您已經(jīng)看到可以使用依賴(lài)項(xiàng),yield并且可以使用try捕獲異常的塊。

它可能是誘人引發(fā)HTTPException的退出代碼或類(lèi)似,后yield。但它不會(huì)工作。

依賴(lài)中的退出代碼在Exception Handlers之后yield執(zhí)行。在退出代碼中(在 之后)沒(méi)有任何捕獲依賴(lài)項(xiàng)引發(fā)的異常。 yield

因此,如果您在HTTPException之后引發(fā) ,則yield捕獲HTTPExceptions 并返回 HTTP 400 響應(yīng)的默認(rèn)(或任何自定義)異常處理程序?qū)⒉辉儆糜诓东@該異常。

這就是允許任何設(shè)置在依賴(lài)項(xiàng)(例如數(shù)據(jù)庫(kù)會(huì)話)中的東西,例如,被后臺(tái)任務(wù)使用。

后臺(tái)任務(wù)在響應(yīng)發(fā)送后運(yùn)行。所以沒(méi)有辦法提高 anHTTPException因?yàn)樯踔翛](méi)有辦法改變已經(jīng)發(fā)送的響應(yīng)。

但是,如果后臺(tái)任務(wù)創(chuàng)建了數(shù)據(jù)庫(kù)錯(cuò)誤,至少您可以使用 回滾或干凈地關(guān)閉依賴(lài)項(xiàng)中的會(huì)話yield,并且可以記錄錯(cuò)誤或?qū)⑵鋱?bào)告給遠(yuǎn)程跟蹤系統(tǒng)。

如果您知道某些代碼可能引發(fā)異常,請(qǐng)執(zhí)行最正常/“Pythonic”的操作并try在該部分代碼中添加一個(gè)塊。

如果您想在返回響應(yīng)之前處理自定義異常并可能修改響應(yīng),甚至可能引發(fā)HTTPException,請(qǐng)創(chuàng)建自定義異常處理程序。

提示

您仍然可以引發(fā)異常,包括HTTPException 之前的yield。但不是之后。

執(zhí)行的順序或多或少像這個(gè)圖。時(shí)間從上到下流動(dòng)。每一列都是交互或執(zhí)行代碼的部分之一。



信息

只會(huì)向客戶(hù)端發(fā)送一個(gè)響應(yīng)。它可能是錯(cuò)誤響應(yīng)之一,也可能是來(lái)自路徑操作的響應(yīng)。

在發(fā)送這些響應(yīng)之一后,不能再發(fā)送其他響應(yīng)。

提示

此圖顯示HTTPException,但您也可以引發(fā)任何其他異常,您為其創(chuàng)建自定義異常處理程序。并且該異常將由該自定義異常處理程序而不是依賴(lài)項(xiàng)退出代碼處理。

但是如果你引發(fā)一個(gè)異常處理程序沒(méi)有處理的異常,它將由依賴(lài)項(xiàng)的退出代碼處理。

上下文管理器

什么是“上下文管理器”

“上下文管理器”是您可以在with語(yǔ)句中使用的任何 Python 對(duì)象。

例如,您可以使用with讀取文件

with open("./somefile.txt") as f:
    contents = f.read()
    print(contents)

在下面,它open("./somefile.txt")創(chuàng)建了一個(gè)稱(chēng)為“上下文管理器”的對(duì)象。

當(dāng)with塊完成時(shí),它確保關(guān)閉文件,即使有異常。

當(dāng)您使用 來(lái)創(chuàng)建依賴(lài)項(xiàng)時(shí)yield,F(xiàn)astAPI會(huì)在內(nèi)部將其轉(zhuǎn)換為上下文管理器,并將其與其他一些相關(guān)工具結(jié)合起來(lái)。

在依賴(lài)項(xiàng)中使用上下文管理器 yield

警告

這或多或少是一個(gè)“高級(jí)”的想法。

如果您剛剛開(kāi)始使用FastAPI,您可能想暫時(shí)跳過(guò)它。

在 Python 中,您可以通過(guò)使用兩種方法創(chuàng)建一個(gè)類(lèi)__enter__()__exit__()來(lái)創(chuàng)建上下文管理器。

您還可以通過(guò)在依賴(lài)函數(shù)中使用 或語(yǔ)句在FastAPI依賴(lài)中使用它們:yieldwithasync with

class MySuperContextManager:
    def __init__(self):
        self.db = DBSession()

    def __enter__(self):
        return self.db

    def __exit__(self, exc_type, exc_value, traceback):
        self.db.close()


async def get_db():
    with MySuperContextManager() as db:
        yield db

提示

創(chuàng)建上下文管理器的另一種方法是:

使用它們來(lái)裝飾帶有單個(gè)yield.

這就是FastAPI 在內(nèi)部用于與yield.

但是您不必為 FastAPI 依賴(lài)項(xiàng)使用裝飾器(并且您不應(yīng)該這樣做)。

FastAPI 將在內(nèi)部為您完成。


以上內(nèi)容是否對(duì)您有幫助:
在線筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號(hào)
微信公眾號(hào)

編程獅公眾號(hào)