You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

为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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.31 22:10:42