如何为返回带类型类方法的Python工厂函数添加类型注解
为返回带类型化类方法的Python工厂函数添加正确的类型注解
我在为返回带有类型化类方法的Python工厂函数添加类型注解时遇到了困难。具体来说,我有一个Factory()工厂函数,用于创建带有.create()类方法的CRUD类,它接收两个参数:
model:对应数据库表的SQLAlchemy模型类schema:Pydantic schema类
初始实现代码如下:
from typing import Type, TypeVar from pydantic import BaseModel from sqlalchemy.orm import DeclarativeBase, Mapped, mapped_column class Base(DeclarativeBase): pass SqlModel = TypeVar("SqlModel", bound=Base) PydanticSchema = TypeVar("PydanticSchema", bound=BaseModel) def Factory(model: Type[SqlModel], schema: Type[PydanticSchema]): class Foo: @classmethod def create(cls, data: schema) -> model: db_model = model(**data.model_dump()) return db_model return Foo class MyModel(Base): name: Mapped[str] = mapped_column(primary_key=True) class MySchema(BaseModel): name: str MyFactory = Factory(MyModel, MySchema) bar = MyFactory.create(MySchema(name="bar"))
我希望通过Factory实例化的类,其.create()方法的类型注解能和传入的model、schema类完全匹配。但当前实现存在问题:
- 使用
TypeVar和Type时,参数data的类型显示为MySchema@Factory,返回类型为MyModel@Factory,无法关联到原始类的类型和方法,不符合预期 - 不使用
TypeVar时,两者类型都会变成Any
请问如何正确添加类型注解,使得调用MyFactory = Factory(MyModel, MySchema)后,MyFactory.create()的参数类型为MySchema,返回类型为MyModel?
编辑补充:我尝试用泛型和双重TypeVar实现了功能,但不确定是否正确或是否滥用了类型系统,希望得到反馈:
SqlModel = TypeVar("SqlModel", bound=Base) PydanticSchema = TypeVar("PydanticSchema", bound=BaseModel) def Factory(model: Type[SqlModel], schema: Type[PydanticSchema]): FooSqlModel = TypeVar("FooSqlModel", bound=model) FooSchema = TypeVar("FooSchema", bound=schema) class Foo(Generic[FooSqlModel, FooSchema]): @classmethod def create(cls, data: FooSchema) -> FooSqlModel: db_model = model(**data.model_dump()) return db_model return Foo[model, schema]
正确的类型注解方案
不需要在工厂函数内部额外定义TypeVar,只需让返回的类继承泛型,并通过外层的TypeVar绑定类型即可。核心是让工厂函数返回携带具体泛型参数的类实例,直接关联传入的model和schema类型。
修改后的代码如下:
from typing import Type, TypeVar, Generic from pydantic import BaseModel from sqlalchemy.orm import DeclarativeBase, Mapped, mapped_column class Base(DeclarativeBase): pass # 定义顶层TypeVar,用于绑定泛型类型 SqlModel = TypeVar("SqlModel", bound=Base) PydanticSchema = TypeVar("PydanticSchema", bound=BaseModel) def Factory(model: Type[SqlModel], schema: Type[PydanticSchema]) -> Type[Generic[SqlModel, PydanticSchema]]: class Foo(Generic[SqlModel, PydanticSchema]): @classmethod def create(cls, data: PydanticSchema) -> SqlModel: db_model = model(**data.model_dump()) return db_model return Foo class MyModel(Base): __tablename__ = "my_model" # 补充表名避免SQLAlchemy警告 name: Mapped[str] = mapped_column(primary_key=True) class MySchema(BaseModel): name: str MyFactory = Factory(MyModel, MySchema) # 此时IDE会正确提示:create方法接收MySchema类型参数,返回MyModel类型 bar = MyFactory.create(MySchema(name="bar"))
方案说明
- 顶层TypeVar绑定:外层定义的
SqlModel和PydanticSchema直接绑定到内部Foo泛型类,类型检查器可追踪到传入的具体类类型。 - 明确返回类型:工厂函数的返回类型标注为
Type[Generic[SqlModel, PydanticSchema]],清晰告知类型检查器返回的是携带具体泛型参数的类。 - 冗余代码移除:内部额外定义
TypeVar属于冗余操作,外层的TypeVar已能完成类型绑定,简化后更符合类型系统设计逻辑。
对尝试方案的反馈
你之前的实现能正常运行,但存在冗余的TypeVar定义:内部的FooSqlModel和FooSchema完全可以被外层的TypeVar替代,无需额外绑定到model和schema实例。这种写法不算“滥用类型系统”,但属于不必要的复杂写法,简化后更清晰易维护。
内容的提问来源于stack exchange,提问作者LTMullineux
相关产品推荐
相关产品推荐

