Pydantic BaseModel
默认值行为探究:为何列表不共享?
本文深入探讨Pydantic中可变对象(如列表)的默认值行为,解释为何使用BaseModel
时,多个实例的列表属性不会共享同一个对象。
问题根源在于以下代码:我们定义一个名为User
的Pydantic BaseModel
,包含一个名为friends
的列表属性,默认值为一个空列表[]
。创建两个User
实例后,修改其中一个实例的friends
属性,另一个实例的friends
属性保持不变。
from typing import List from pydantic import BaseModel class User(BaseModel): friends: List[int] = [] user_1 = User() user_1.friends.append(1) print(user_1.friends) # 输出:[1] user_2 = User() print(user_2.friends) # 输出:[]
然而,如果我们不继承BaseModel
,则两个实例共享同一个列表:
from typing import List class User: friends: List[int] = [] user_1 = User() user_1.friends.append(1) print(user_1.friends) # 输出:[1] user_2 = User() print(user_2.friends) # 输出:[1]
区别在于Pydantic的BaseModel
如何处理默认值。在不使用BaseModel
的情况下,Python类定义机制只创建一次默认列表,所有实例共享该对象。因此,修改user_1.friends
会影响user_2.friends
。
而Pydantic的BaseModel
在实例化每个User
对象时,都会为friends
属性创建一个新的空列表。这是Pydantic为了确保每个实例拥有独立数据副本而设计的。虽然代码中friends
的默认值看起来是一个空列表,但Pydantic在内部创建新的列表对象,避免了共享可变对象导致的数据一致性问题。
这与Pydantic的设计目标密切相关:提供数据验证和模型定义,并保持数据独立性。Pydantic的元类(或其内部机制)在创建实例时负责创建新的默认值对象,保证每个实例拥有独立的friends
列表。即使Pydantic版本更新,底层实现可能变化,但核心目标——保证实例独立性——保持不变。