如何在继承 Pydantic 的 BaseModel 后定义类属性?

18
在普通的Python类中,我可以定义类属性,例如:
class Example:
  x = 3
  def __init__(self):
    pass

如果我执行Example.xExample().x,那么输出结果将是3

当我继承pydantic的BaseModel时,我无法确定如何定义类属性,因为通常定义类属性的方式会被BaseModel覆盖。

例如:

class Example(BaseModel):
  x = 3

print(Example.x)
--> type object 'Example' has no attribute 'x'

我希望能够定义类级别的属性。请问这个正确的方法或语法是什么?


1
如果你只是想要一个数据容器,可以不用实例化就能调用它,为什么不使用 dataclass 呢? - Bastien B
恐怕不行。我需要我的类中Basemodel的其他功能。而且更广泛地说,如果我想要一些不同上下文的类属性呢?例如,可变类属性,这样我就可以在更新一个类时更新所有类。 - Alan
2个回答

36

好的,我最终弄清楚了。答案在于数据类如何处理类变量。(回想起来这应该很明显,但是人总是要犯错误)

有一种类型叫做ClassVar。当一个类的属性被标注为ClassVar时,它就成为了一个类变量。

class Example(BaseModel):
  x: ClassVar[int] = 3
  y: int


# Usage
print(Example().x)
>>> ValidationError

print(Example.x)
>>> 3


6
ClassVar 定义在 typing 中,所以不要忘记导入它 (from typing import ClassVar)。 - ThibThib
感谢您的发现。我也在文档中找到了它:https://pydantic-docs.helpmanual.io/usage/models/#automatically-excluded-attributes - Billy Chan

-3
你正确地定义了类级别的属性,但是你读取它的方式不对。 当从这个类中读取变量时,你应该通过另一个定义该类的变量来访问该类。像这样:
from pydantic import BaseModel
class User(BaseModel):
  x = 3
user = User()
print(user.x)

输出结果为:3


1
嗨Leo,那只是实例化类而已。我在问题中提到,类属性可以通过Example.xExample().x两种方式访问。我想要的是通过Example.x访问类属性,而不必实例化。原因是,有很多时候我们不能免费实例化一个类。也许它会在__init__上改变自己,或者它只有一些非可选字段,其值我没有在内存中。此外,为了节省内存,我不想必须实例化类来获取我知道存在的信息(并且可以在没有BaseModel的情况下获得)。 - Alan

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接