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

如何阻止Pydantic在将模型传入另一模型构造函数时复制实例?

解决Pydantic嵌套模型实例复制问题

你遇到的这个问题是Pydantic的默认行为导致的——当你把一个已实例化的模型传入另一个模型的构造函数时,Pydantic会重新解析并创建一个新的模型实例,而不是直接复用传入的对象,这就导致了parent.child和原child不是同一个引用。

要实现让parent.child和原实例共享同一个引用,从而修改原实例时同步反映到嵌套字段中,可以通过自定义模型验证器来拦截解析过程,直接保留传入的实例。

解决方案(Pydantic v2)

使用model_validator(mode='before')装饰器,在Pydantic进行常规解析之前检查并保留已有的模型实例:

from pydantic import BaseModel, model_validator

class Child(BaseModel):
    value: int = 0  # 加个属性方便测试同步修改

class Parent(BaseModel):
    child: Child

    @model_validator(mode='before')
    def keep_child_instance(cls, values):
        # 检查传入的child是否已经是Child实例,如果是直接保留
        child_instance = values.get('child')
        if isinstance(child_instance, Child):
            values['child'] = child_instance
        return values

# 测试代码
child = Child()
parent = Parent(child=child)
assert parent.child is child  # 现在断言成功!

# 验证修改同步
child.value = 10
assert parent.child.value == 10  # 修改原实例后,parent.child也同步更新

原理说明

mode='before'的模型验证器会在Pydantic对输入数据进行解析和验证之前执行。我们在这里判断如果传入的child已经是Child类的实例,就直接把它赋值回values字典,跳过Pydantic默认的实例化流程,这样就能保留原对象的引用。

这种方法还兼容常规的字典传入方式——如果你传入的是符合Child结构的字典,Pydantic依然会正常解析成Child实例,不会影响原有功能。

针对Pydantic v1的兼容方案

如果你还在使用Pydantic v1,可以用@validator装饰器配合pre=True参数实现同样的效果:

from pydantic import BaseModel, validator

class Child(BaseModel):
    value: int = 0

class Parent(BaseModel):
    child: Child

    @validator('child', pre=True)
    def keep_child_instance(cls, v):
        if isinstance(v, Child):
            return v
        return v

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.29 00:47:41