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

如何在Pydantic抽象模型中用私有字段验证公共字段?

Pydantic中用私有字段+抽象方法实现字段验证的方案

这个需求完全可以实现,但你当前的代码存在逻辑顺序问题,导致验证器拿不到_nai_pattern的值——因为Pydantic的字段验证是在实例初始化(__init__)之前执行的,等check_nai_format跑起来的时候,_nai_pattern还没被赋值,而且因为是私有字段,也不会出现在验证器的values参数里。

问题出在哪

  1. 验证时机不对:@validator是类级别的逻辑,执行时间早于__init__,实例还没创建,你在__init__里给_nai_pattern赋值的代码根本还没运行。
  2. 私有字段不进验证上下文:就算你提前设置了_nai_pattern,underscore_attrs_are_private = True会让Pydantic把它当成私有属性,不会把它放到验证器的values字典里供你调用。

修正后的实现方案

我们可以把set_nai_pattern改成抽象类方法,让验证器直接调用子类的类方法获取预期的NAI格式,同时保留私有字段存这个值(如果需要的话)。

Pydantic v1 版本代码

from abc import ABC, abstractmethod
from pydantic import BaseModel, validator


class BaseAsset(BaseModel, ABC):
    amount: int
    precision: int
    nai: str
    _nai_pattern: str = None

    @classmethod
    @abstractmethod
    def set_nai_pattern(cls) -> str:
        pass

    @validator('nai')
    def check_nai_format(cls, v):
        expected_pattern = cls.set_nai_pattern()
        if v != expected_pattern:
            raise ValueError(f"NAI格式错误,必须是{expected_pattern}")
        return v

    def __init__(self, **kwargs):
        super().__init__(**kwargs)
        # 实例化后把模式存入私有字段
        object.__setattr__(self, '_nai_pattern', self.set_nai_pattern())

    class Config:
        underscore_attrs_are_private = True


class AssetHive(BaseAsset):
    @classmethod
    def set_nai_pattern(cls):
        return "@@000000021"

Pydantic v2 版本代码

如果用v2的话,推荐用@field_validator替代旧的@validator,还可以用model_post_init替代手动重写__init__:

from abc import ABC, abstractmethod
from pydantic import BaseModel, field_validator


class BaseAsset(BaseModel, ABC):
    amount: int
    precision: int
    nai: str
    _nai_pattern: str = None

    @classmethod
    @abstractmethod
    def set_nai_pattern(cls) -> str:
        pass

    @field_validator('nai')
    def check_nai_format(cls, v):
        expected_pattern = cls.set_nai_pattern()
        if v != expected_pattern:
            raise ValueError(f"NAI格式错误,必须是{expected_pattern}")
        return v

    def model_post_init(self, __context):
        self._nai_pattern = self.set_nai_pattern()

    class Config:
        underscore_attrs_are_private = True


class AssetHive(BaseAsset):
    @classmethod
    def set_nai_pattern(cls):
        return "@@000000021"

核心调整点

  • 把set_nai_pattern改成抽象类方法:验证器本身是类方法,这样就能直接调用cls.set_nai_pattern()拿到子类定义的格式,不用依赖实例属性。
  • 私有字段_nai_pattern仅用于实例化后存值:如果不需要在实例里保留这个模式,直接删掉私有字段,验证器里直接调用类方法就行。
  • 验证逻辑和子类绑定:每个子类的NAI格式验证会自动用自己定义的模式,符合抽象类的设计初衷。

内容的提问来源于stack exchange,提问作者Jakub_Z

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.25 04:33:19