如何阻止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
相关产品推荐
相关产品推荐

