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

Pydantic模型中下划线属性名的处理机制及与普通Python类的差异

Pydantic如何处理带下划线的属性名?

在Pydantic模型中,带下划线的属性命名存在特殊行为,和普通Python类的表现不同,测试结果显示了一些看似“意外”的错误。

测试代码

from pydantic import BaseModel

class PydanticClass(BaseModel):
    a: int = "AAA"
    _z: int = "_Z_Z_Z"

    @classmethod
    def get_a(cls):
        return cls.a

    @classmethod
    def get_z(cls):
        return cls._z

class NonPydanticClass:
    a: int = "AAA"
    _z: int = "_Z_Z_Z"

    @classmethod
    def get_a(cls):
        return cls.a

    @classmethod
    def get_z(cls):
        return cls._z

print("PYDANTIC MODEL CLASS TEST:")
pydantic_instance = PydanticClass()

try:
    msg1, msg2 = "SUCCESS", f"{pydantic_instance.get_a()}"
except Exception as e:
    msg1, msg2 = "ERROR", f"{e}"
print('{0:<7} :: {1:<27} :: {2:<65} :: {3}'.format(msg1, "1 pydantic_instance.get_a()", "在类方法中访问非下划线属性名", msg2))

try:
    msg1, msg2 = "SUCCESS", f"{pydantic_instance.get_z()}"
except Exception as e:
    msg1, msg2 = "ERROR", f"{e}"
print('{0:<7} :: {1:<27} :: {2:<65} :: {3}'.format(msg1, "2 pydantic_instance.get_z()", "在类方法中访问下划线属性名", msg2))

try:
    msg1, msg2 = "SUCCESS", f"{PydanticClass.a}"
except Exception as e:
    msg1, msg2 = "ERROR", f"{e}"
print('{0:<7} :: {1:<27} :: {2:<65} :: {3}'.format(msg1, "3 PydanticClass.a ", "以‘静态属性’方式访问非下划线属性名", msg2))

try:
    msg1, msg2 = "SUCCESS", f"{PydanticClass._z}"
except Exception as e:
    msg1, msg2 = "ERROR", f"{e}"
print('{0:<7} :: {1:<27} :: {2:<65} :: {3}'.format(msg1, "4 PydanticClass._z", "以‘静态属性’方式访问下划线属性名", msg2))

print("\nNON PYDANTIC CLASS TEST:")
nom_pydantic_instance = NonPydanticClass()

try:
    msg1, msg2 = "SUCCESS", f"{nom_pydantic_instance.get_a()}"
except Exception as e:
    msg1, msg2 = "ERROR", f"{e}"
print('{0:<7} :: {1:<27} :: {2:<65} :: {3}'.format(msg1, "1 class_instance.get_a()", "在类方法中访问非下划线属性名", msg2))

try:
    msg1, msg2 = "SUCCESS", f"{nom_pydantic_instance.get_z()}"
except Exception as e:
    msg1, msg2 = "ERROR", f"{e}"
print('{0:<7} :: {1:<27} :: {2:<65} :: {3}'.format(msg1, "2 class_instance.get_z()", "在类方法中访问下划线属性名", msg2))

try:
    msg1, msg2 = "SUCCESS", f"{NonPydanticClass.a}"
except Exception as e:
    msg1, msg2 = "ERROR", f"{e}"
print('{0:<7} :: {1:<27} :: {2:<65} :: {3}'.format(msg1, "3 PydanticClass.a ", "以‘静态属性’方式访问非下划线属性名", msg2))

try:
    msg1, msg2 = "SUCCESS", f"{NonPydanticClass._z}"
except Exception as e:
    msg1, msg2 = "ERROR", f"{e}"
print('{0:<7} :: {1:<27} :: {2:<65} :: {3}'.format(msg1, "4 PydanticClass._z", "以‘静态属性’方式访问下划线属性名", msg2))

测试结果

PYDANTIC MODEL CLASS TEST:
ERROR   :: 1 pydantic_instance.get_a() :: 在类方法中访问非下划线属性名      :: type object 'PydanticClass' has no attribute 'a'
SUCCESS :: 2 pydantic_instance.get_z() :: 在类方法中访问下划线属性名          :: _Z_Z_Z
ERROR   :: 3 PydanticClass.a           :: 以‘静态属性’方式访问非下划线属性名 :: type object 'PydanticClass' has no attribute 'a'
SUCCESS :: 4 PydanticClass._z          :: 以‘静态属性’方式访问下划线属性名    :: _Z_Z_Z

NON PYDANTIC CLASS TEST:
SUCCESS :: 1 class_instance.get_a()    :: 在类方法中访问非下划线属性名      :: AAA
SUCCESS :: 2 class_instance.get_z()    :: 在类方法中访问下划线属性名          :: _Z_Z_Z
SUCCESS :: 3 PydanticClass.a           :: 以‘静态属性’方式访问非下划线属性名 :: AAA
SUCCESS :: 4 PydanticClass._z          :: 以‘静态属性’方式访问下划线属性名    :: _Z_Z_Z

原因解释

Pydantic的核心逻辑是:

  • 非下划线开头的属性会被识别为模型字段,这些字段不会保留为类的直接属性,而是被存储到模型的__fields__字典中。所以直接通过PydanticClass.a访问会报错,类方法里的cls.a也找不到该属性——因为它已经不是类的固有属性了。
  • 下划线开头的属性不会被Pydantic当作模型字段处理,完全保留了普通Python类属性的特性,因此不管是通过类直接访问,还是在类方法里调用,都能正常获取到值。

普通Python类没有这种字段处理逻辑,所有属性都会直接绑定在类上,因此不管属性名是否带下划线,所有访问方式都能成功。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.28 22:53:11