在类型注解中忽略某个字段

0 投票
1 回答
73 浏览
提问于 2025-04-14 18:06

如果我有一个叫做pydantic的类,像这样:

from typing import Annotated, get_origin
from pydantic import BaseModel

class IgnorableBaseModel(BaseModel):
    _ignored: ClassVar[dict[str, Any]] = {}

    def __getattr__(self, attr):
        """do something with _ignored, else fallback to default"""

    def __init_subclass__(cls, **kwargs) -> None:
        del_keys = []
        for key, annotation in cls.__annotations__.items():
            if key.startswith("_"):  # exclude protected/private attributes
                continue
            if get_origin(annotation) is Annotated:
                if get_args(annotation)[1] == "ignore me"
                    cls._ignored[key] = cls.__annotations__[key]
                    del_keys.append(key)
        for key in del_keys:
            del cls.__annotations__[key]

class MyClass(IgnorableBaseModel):
    name: Annotated[str, "ignore me"]   # ignore this
    x: int

我在这个类里用的一个变量是在__init__方法里定义的,然后通过__getattr__来访问,所以我不能给它设置一个值。请问有没有办法让mypy忽略这个问题,或者我是不是每次都得像这样重写初始化参数:

class MyClass(IgnorableBaseModel):
    name: Annotated[str, "ignore me"]
    x: int

    def __init__(self, x: int):
        self.x = x

如果能有一个注释可以加上,告诉mypy这个变量在初始化时不需要就好了。

这里的“ignore me”是用来表示我不想看到这个错误的:

Missing named argument "name" for "MyClass"Mypycall-arg

为了提供一些背景信息,我正在尝试制作一个Python的领域特定语言(DSL),所以能够对一些属性进行类型提示,但实际上不需要给它们赋值,这样会很有帮助。

1 个回答

1

如果你想让 name 这个属性在 __init__ 方法中被定义,而不需要在创建对象时传入它的值,可以使用 Fieldinit 参数。

from typing import Annotated
from pydantic import BaseModel, Field

class MyClass(BaseModel):
    name: Annotated[str, Field(init=False)]
    x: int

这也可以写成

class MyClass(BaseModel):
    name: str = Field(init=False)
    x: int

这样生成的 __init__ 方法只会期待一个 x 的参数,至于 MyClass 的实例中的 name 属性怎么定义,就得靠我们自己来处理了。我们可以使用默认值、默认工厂,或者自己定义一个 __init__ 方法,或者使用 Pydantic 提供的其他技巧。

撰写回答