我有两个pydantic模型,第二个继承了第一个:
class RandomBaseModel(pydantic.BaseModel):
foo: typing.Any
class RandomSpecializedModel(RandomBaseModel):
foo: str
然后我有一个函数,它接受一些数据和一个模型,用于实例化响应:
def do_something(
data: typing.Any,
response_model: typing.Type[RandomBaseModel] = RandomBaseModel
) -> RandomBaseModel:
response = response_model(foo=data)
print(f"---{type(response)}---")
return response
最后,该函数的结果存储在类型化变量中:
value_1: RandomBaseModel = do_something(42)
value_2: RandomSpecializedModel = do_something("42", response_model=RandomSpecializedModel)
这个执行没有任何问题,并按预期工作,当response_model
被省略时,do_something
函数实例化一个RandomBaseModel
,当它被指示使用它时,实例化一个RandomSpecializedModel
。下面是输出:
---<class '__main__.RandomBaseModel'>---
---<class '__main__.RandomSpecializedModel'>---
但这并不让我满意,我在value_2: RandomSpecializedModel = do_something("42", response_model=RandomSpecializedModel)
线上抱怨这条消息:
error: Incompatible types in assignment (expression has type "RandomBaseModel", variable has type "RandomSpecializedModel") [assignment]
我怎么能告诉我,这个函数返回pydantic模型的实例传递作为response_model
参数?
要明确:我正在寻找一种方法来指示我的函数可以返回RandomBaseModel
实例,RandomSpecializedModel
或任何RandomBaseModel
的子类的实例。
我发现了一些类似的问题,其答案建议使用TypeVar,所以我试图为此改变do_something
函数:
AnyRandomBaseModel = typing.TypeVar("AnyRandomBaseModel", bound=RandomBaseModel)
def do_something(
data: typing.Any,
response_model: typing.Type[AnyRandomBaseModel] = RandomBaseModel
) -> AnyRandomBaseModel:
response = response_model(foo=data)
print(f"---{type(response)}---")
return response
虽然它仍然按预期执行,但mypy现在报错:
error: Incompatible default for argument "response_model" (default has type "Type[RandomBaseModel]", argument has type "Type[AnyRandomBaseModel]")
您可能应该将基本模型改为泛型。
from typing import TypeVar, Generic
T = TypeVar('T')
class RandomBaseModel(pydantic.BaseModel, Generic[T]):
foo: T
class RandomSpecializedModel(RandomBaseModel[str]):
foo: str # you might not need this line
def do_something(
data: T,
response_model: typing.Type[RandomBaseModel[T]] = RandomBaseModel
) -> RandomBaseModel[T]:
response = response_model(foo=data)
print(f"---{type(response)}---")
return response
尝试使用类型的Union:
def do_something(
data: typing.Any,
response_model: typing.Type[RandomBaseModel] = RandomBaseModel
) -> Union[RandomBaseModel,RandomSpecializedModel]
我知道这很奇怪,因为你的一个类从另一个继承,但我认为你没有选择
仅供参考,因为我对它不太满意,我用typing.cast
解决了我的问题:
value_2: RandomSpecializedModel = typing.cast(
RandomSpecializedModel,
do_something("42", response_model=RandomSpecializedModel)
)
这对我来说不是很满意,为了取悦Mypy而使它如此冗长,但至少它可以在没有使用# type: ignore[]
静音Mypy的情况下工作。所以这就足够好了……:/