FastAPI 深入学习:利用__call__方法实现动态依赖项_初始化

在Python中,__init____call__ 是两个特殊的方法,它们在类的上下文中有特定的用途:

  1. __init__ 方法:
  • 这是类的初始化方法,当一个实例被创建时,它会被自动调用。
  • 它通常用于接收初始化参数并设置实例的初始状态。
  • 在你的示例中,FixedContentQueryChecker 类的 __init__ 方法接收一个参数 fixed_content,并将其存储在实例变量 self.fixed_content 中。这个变量随后可以在类的其他方法中使用。
  1. __call__ 方法:
  • 当一个实例被用作函数时,__call__ 方法会被自动调用。
  • 这意味着如果你有一个类的实例,并且你像调用函数一样调用这个实例(即 instance()),Python 会寻找并执行 __call__ 方法。
  • 在你的示例中,__call__ 方法定义了 FixedContentQueryChecker 类的行为,使其可以像函数一样被调用。它接收一个参数 q,这是一个字符串,默认为空字符串。方法内部检查 self.fixed_content 是否为 q 的子串,如果是,则返回 True,否则返回 False
from typing import Annotated

from fastapi import Depends, FastAPI

app = FastAPI()

class FixedContentQueryChecker:
    def __init__(self, fixed_content: str):
        self.fixed_content = fixed_content

    def __call__(self, q: str = ""):
        if q:
            return self.fixed_content in q
        return False

checker = FixedContentQueryChecker("bar")

@app.get("/query-checker/")
async def read_query_check(fixed_content_included: Annotated[bool, Depends(checker)]):
    return {"fixed_content_in_query": fixed_content_included}

在你的FastAPI应用示例中,FixedContentQueryChecker 类被用作一个依赖项,它检查查询参数中是否包含特定的固定内容。这里是详细步骤:

  • FixedContentQueryChecker 类被实例化为 checker,初始化时传入了字符串 "bar"
  • 在FastAPI路由装饰器 @app.get("/query-checker/") 下,定义了一个异步视图函数 read_query_check
  • 这个视图函数使用了一个依赖项 Annotated[bool, Depends(checker)],它告诉FastAPI在调用视图函数之前,先调用 checker 实例(即调用它的 __call__ 方法)。
  • 依赖项的参数 q 默认为空字符串,但FastAPI会将查询参数 q 的值传递给 checker 实例。
  • checker 实例的 __call__ 方法检查传递给它的查询参数 q 是否包含 "bar" 字符串,并将结果作为 fixed_content_included 参数传递给 read_query_check 视图函数。
  • 视图函数返回一个字典,包含一个键 fixed_content_in_query,其值是 checker 实例检查的结果。

这样,当用户发送GET请求到 /query-checker/ 并提供查询参数 q 时,FastAPI会调用 checker 实例来检查 q 是否包含 "bar",并将结果作为JSON响应返回。

补课:

在Python中,当你想让一个类的实例表现得像一个函数时,你可以在类定义中实现 __call__ 方法。这个方法在实例被调用(使用圆括号 ())时自动触发。这使得对象可以采用类似函数的调用方式。

下面是一个简单的例子,演示如何使用 __call__ 方法:

class Greeting:
    def __init__(self, name):
        self.name = name

    def __call__(self):
        return f"Hello, {self.name}!"

# 创建一个Greeting类的实例
greeter = Greeting("World")

# 调用这个实例,就像它是一个函数一样
print(greeter())  # 输出: Hello, World!

创建一个类的实例跟调用实例是不一样的。

在这个例子中,Greeting 类有一个 __init__ 方法来初始化实例,接收一个名字 name__call__ 方法则定义了当实例被调用时应该执行的操作,这里是返回一个问候语。

另一个例子:创建一个简单的计算器

让我们创建一个可以像函数一样调用的简单计算器类:

class Calculator:
    def __init__(self, a=0, b=0):
        self.a = a
        self.b = b

    def __call__(self, operation):
        if operation == "add":
            return self.a + self.b
        elif operation == "subtract":
            return self.a - self.b
        elif operation == "multiply":
            return self.a * self.b
        elif operation == "divide":
            if self.b != 0:
                return self.a / self.b
            else:
                return "Error: Division by zero"

# 创建一个Calculator实例
calc = Calculator(10, 5)

# 调用实例来执行加法
print(calc("add"))  # 输出: 15

# 调用实例来执行减法
print(calc("subtract"))  # 输出: 5

# 调用实例来执行乘法
print(calc("multiply"))  # 输出: 50

# 调用实例来执行除法
print(calc("divide"))  # 输出: 2.0

# 尝试除以零
print(calc("divide"))  # 输出: Error: Division by zero

在这个例子中,Calculator 类的 __call__ 方法接收一个操作参数 operation,根据传入的操作类型(加法、减法、乘法、除法),执行相应的运算。

通过实现 __call__ 方法,类的实例可以被直接调用,这使得它们在某些情况下非常有用,特别是在需要自定义函数对象或实现回调函数时。