我正try 在带有定制__init_函数的PYDANIC中使用继承.我有父类(FISH)和子类(SHARK),它们在初始化时都需要比设置字段(在MWE中由一个额外的print语句表示)更多的初始化.所以我需要重写他们的初始信息.

我试过:

class fish(BaseModel):
    name: str
    def __init__(self, name):
        super().__init__(name=name)
        print("Fish initialization successful!")
        

class shark(fish):
    color: str
    def __init__(self, name, color):
        super().__init__(name=name)
        self.color=color
        print("Shark initialization successful!")
        
f = fish(name="nemo")
print(f)
s = shark(name="bruce", color="grey")

但这引发了一个验证错误:

Fish initialization successful!
name='nemo'
---------------------------------------------------------------------------
ValidationError                           Traceback (most recent call last)
Cell In[149], line 17
     15 f = fish(name="nemo")
     16 print(f)
---> 17 s = shark(name="bruce", color="grey")

Cell In[149], line 11, in shark.__init__(self, name, color)
     10 def __init__(self, name, color):
---> 11     super().__init__(name=name)
     12     self.color=color
     13     print("Shark initialization successful!")

Cell In[149], line 4, in fish.__init__(self, name)
      3 def __init__(self, name):
----> 4     super().__init__(name=name)
      5     print("Fish initialization successful!")

File ~/Desktop/treeline_wt/1588-yieldmodeling-integration/device-predictions/.venv/lib/python3.9/site-packages/pydantic/main.py:341, in pydantic.main.BaseModel.__init__()

ValidationError: 1 validation error for shark
color
  field required (type=value_error.missing)

我从一位有效的同事那里得到的解决方案是:

class fish(BaseModel):
    name: str
    def __init__(self, **kwargs):
        super().__init__(**kwargs)
        print("Fish initialization successful!")
        

class shark(fish):
    color: str
    
    def __init__(self, **kwargs):
        super().__init__(**kwargs)
        print("Shark initialization successful!")
        

# f = fish(name="nemo")
# print(f)
s = shark(name="bruce", color="grey")

在判断时,其仅在鱼super().__init__接收到color关键字时才起作用,即,将其改变为super().__init__(name=kwargs['name'])会抛出相同的验证错误.这让我感到困惑,我不明白为什么鱼类需要知道它的子类的任何属性.我该如何理解这一点?

推荐答案

这与Fish需要了解Shark上定义的任何字段无关.它与BaseModel.__init__了解任何给定模型具有哪些字段,以及根据这些字段验证所有关键字参数有关.

您需要记住,lot是在任何模型类during class creation的"幕后"发生的,也就是说,在您初始化它的任何特定实例之前.元类对此负责.

从本质上讲,你需要这样思考Shark定义过程:

  1. 读取Shark类命名空间.
  2. 收集注释/属性(在本例中为color: str).
  3. 字段就是从这些字段中创建的.
  4. 父类的字段(在本例中是Fish中的name)被添加.
  5. Shark的所有字段(加上验证器和一堆其他东西)都已完全构造好.它现在具有字段namecolor.

BaseModel.__init__方法将始终查看在给定模型上定义的all the fields,并根据这些字段验证所提供的关键字参数.

当您从Shark.__init__内部调用super().__init__(name=name)时,您基本上是在调用Fish.__init__(self, name=name),也就是将(未初始化的)Shark实例selfname参数传递给Fish.__init__.

然后从Fish.__init__内部再次调用super().__init__(name=name),这意味着您正在调用BaseModel.__init__(self, name=name),并且再次只将未完成的Shark实例和关键字参数name传递给它.(请记住,self仍然是Shark对象.)

但是BaseModel.__init__会查看它得到的Shark实例,看到Shark类有two个为它定义的字段(namecolor),它们都不是可选的/没有缺省值.它将看到您只提供了name关键字参数,但未能提供color.因此,它将筹集相应的ValidationError.

然后您try 手动分配self.color = color并不重要,因为这条线甚至从未到达过.

这就是为什么您必须始终将与字段相关的关键字参数"向上链"传递allBaseModel.__init__.这就是为什么您的第二个代码片段中的代码可以正常工作的原因.

乍一看,这似乎并不直观,但Pydtic模型并不是简单的数据类.在幕后发生了许多事情,这就施加了一些限制,不幸的是,这些限制有时没有文档记录(就像本例中一样),只有当您真正深入到源代码中时,这些限制才会变得清晰.

Python相关问答推荐

用ctype构建指针链

带有计数值的Pandas数据帧

try 使用tensorFlow.keras.models时optree Import错误

使用Python进行网页抓取,没有页面

将列表中的元素替换为收件箱中的元素

查找下一个值=实际值加上使用极点的50%

Python中的函数中是否有充分的理由接受float而不接受int?

使用polars .滤镜进行切片速度比pandas .loc慢

如何使用Google Gemini API为单个提示生成多个响应?

线性模型PanelOLS和statmodels OLS之间的区别

如何使用pandasDataFrames和scipy高度优化相关性计算

在Python中处理大量CSV文件中的数据

删除最后一个pip安装的包

用NumPy优化a[i] = a[i-1]*b[i] + c[i]的迭代计算

如何在Python脚本中附加一个Google tab(已经打开)

为什么抓取的HTML与浏览器判断的元素不同?

将scipy. sparse矩阵直接保存为常规txt文件

如何在两列上groupBy,并使用pyspark计算每个分组列的平均总价值

重置PD帧中的值

人口全部乱序 - Python—Matplotlib—映射