为Pydantic子类属性动态更新类型提示,解决类型检查报错
解决方案
1. 泛型Filter类 + 元类动态类型注入
定义泛型Filter[T]类,封装原属性类型T并实现所需运算符(__gt__、__neg__等)。通过自定义元类,在子类创建时将类属性的类型提示替换为Filter[T],既保留Pydantic原字段的验证逻辑,又让类型检查器识别类属性返回值为Filter对象。
示例代码:
from typing import Generic, TypeVar, Any from datetime import datetime from pydantic import BaseModel from pydantic._internal._model_construction import ModelMetaclass T = TypeVar("T") class Filter(Generic[T]): def __init__(self, field_name: str): self.field_name = field_name def __gt__(self, value: T) -> dict[str, Any]: return {"field": self.field_name, "op": ">", "value": value} def __neg__(self) -> dict[str, Any]: return {"field": self.field_name, "order": "desc"} class BaseModelMeta(ModelMetaclass): def __getattr__(cls, name: str) -> Filter[Any]: if name in cls.model_fields: field_type = cls.model_fields[name].type_ return Filter[field_type](name) raise AttributeError(f"{cls.__name__} has no attribute {name}") class BaseDBModel(BaseModel, metaclass=BaseModelMeta): class Config: orm_mode = True class User(BaseDBModel): age: int birth_date: datetime
2. 使用Annotated标注双重类型
用Annotated为字段同时标注原类型和Filter类型,配合类型检查器插件(如mypy插件)识别类属性访问时的实际返回类型。
示例代码:
from typing import Annotated, TypeVar from datetime import datetime from pydantic import BaseModel T = TypeVar("T") Filterable = Annotated[T, "filterable"] class User(BaseDBModel): age: Filterable[int] birth_date: Filterable[datetime]
需编写对应类型检查器插件,将Filterable[T]映射为类属性访问时返回Filter[T],适合对类型系统有深入了解的场景。
3. 为Filter实现原类型兼容的Protocol
定义包含原类型核心方法的Protocol,让Filter类实现该Protocol,同时添加自定义运算符。类型检查器会认为Filter是原类型的兼容类型,避免运算符报错。
示例代码:
from typing import Protocol, TypeVar from datetime import datetime T = TypeVar("T", covariant=True) class FilterableType(Protocol[T]): def __eq__(self, other: T) -> bool: ... class Filter(FilterableType[T]): def __init__(self, field_name: str): self.field_name = field_name def __eq__(self, other: T) -> dict[str, Any]: return {"field": self.field_name, "op": "=", "value": other} def __gt__(self, value: T) -> dict[str, Any]: return {"field": self.field_name, "op": ">", "value": value} def __neg__(self) -> dict[str, Any]: return {"field": self.field_name, "order": "desc"}
4. 临时解决方案:使用typing.cast
在使用时通过cast显式转换类型,告诉类型检查器当前对象为Filter类型,适合小范围临时场景。
示例代码:
from typing import cast sort_expr = -cast(Filter[datetime], User.birth_date)
内容的提问来源于stack exchange,提问作者Fredrik Nilsson
相关产品推荐
相关产品推荐

