python-3.x 将生成器传递给Depends如何使生成器像上下文管理器一样工作?

wixjitnu  于 2023-02-06  发布在  Python
关注(0)|答案(1)|浏览(98)

我正在浏览一个关于快速api的教程,我遇到了类似下面的内容

def get_db():
    try:
        db = SessionLocal()
        yield db
    finally:
        print("from finally block")
        db.close()
@app.get("/")
async def read_all(db: Session = Depends(get_db)):
    res = db.query(models.Todos).all()
    print("from endpoint")
    return res

结果

INFO:     127.0.0.1:39088 - "GET /openapi.json HTTP/1.1" 200 OK
from endpoint
INFO:     127.0.0.1:39088 - "GET / HTTP/1.1" 200 OK
from finally block

为什么Depends(get_db)看起来像某种上下文管理器?。"from finally block"打印语句直到read_all方法结束时才执行
做一些类似

class SomeDependency:
    def __enter__(self):
        print("entering")
    def __exit__(self, exc_type, exc_val, exc_tb):
        print("exited")

def hello():
    try:
        yield SomeDependency()
    finally:
        print("yolo")

if __name__ == "__main__":
   next(hello())

finally块在调用next之后立即执行。
什么原因get_dbfinally块在传递给Depends时没有立即执行?

bnl4lu3b

bnl4lu3b1#

你似乎没有清楚地理解上下文管理器和生成器的概念。基本上它们是完全不相关的不同概念。我将简要地解释它们。
上下文管理器是with语句特性的一部分,它是try/finally块的模板代码的语法糖,确保完成事情。请参阅参考资料以了解详细信息。在第二个示例中,没有涉及上下文管理器,因为没有with语句。
生成器是定义迭代器的样板代码的语法糖。(但从实现的Angular 来看,它是一个相当复杂的特性,称为coroutine。)请参阅参考资料以了解详细信息。在第二个示例中,finally子句将在hello()返回的迭代器结束时(当引用计数达到零时)执行。
虽然我之前说过这两者完全无关,但实际上还是有一点关系的--定义上下文管理器类的锅炉代码的语法糖,通过生成器定义上下文管理器,如下所示(从参考文献中删除并编辑)。

from contextlib import contextmanager

@contextmanager
def managed_resource(...):
    resource = acquire_resource(...)
    try:
        yield resource
    finally:
        release_resource(resource)

with managed_resource(...) as resource:
    ...

返回到FastAPI Depends,如果你给予一个生成器作为参数,它会使用上面的特性在内部创建一个上下文管理器,你可以看到它的实现。

相关问题