pydantic 对象的陷阱
Table of Contents
陷阱
在 Python 中,类成员在所有实例之间是共享的,例如以下代码,friends 是一个类成员(而不是实例成员),所有 User 实例都会共享同一个 friends 列表。也就是说,对一个实例的 friends 列表进行修改,会影响到其他实例的 friends 列表。
这是因为 friends 是在类定义时定义的,是一个类级别的属性。
示例代码
from datetime import datetime
from pydantic import BaseModel
class User(BaseModel):
id: int
name: str = "Walter Fan"
signup_ts: datetime | None = None
friends: list[int] = []
user1 = User(id=1)
user2 = User(id=2)
user1.friends.append(2)
print(user1.friends) # [2]
print(user2.friends) # [2] (意料之外的结果,因为两者共享了同一个 friends 列表)
解决方法
如果希望 friends 是每个实例独立的,应该将其设为实例属性,而不是类属性。你可以通过 Pydantic 的 Field 和默认工厂实现这一点:
修正代码
from datetime import datetime
from pydantic import BaseModel, Field
class User(BaseModel):
id: int
name: str = "Walter Fan"
signup_ts: datetime | None = None
friends: list[int] = Field(default_factory=list) # 使用 default_factory 创建独立的列表
user1 = User(id=1)
user2 = User(id=2)
user1.friends.append(2)
print(user1.friends) # [2]
print(user2.friends) # [] (正确,两个实例有独立的 friends 列表)
原因
• 使用 Field(default_factory=list) 时,list 是通过 default_factory 动态生成的,每次实例化时都会创建一个新的独立列表。
• 如果直接用 friends: list[int] = [],[] 是在类加载时定义的共享对象。
总结
你的原始代码中,friends 列表会在实例之间共享,因此修改其中一个实例的 friends 会影响到所有实例。使用 Field(default_factory=list) 可以避免此问题,每个实例都有独立的 friends 列表。
Comments |0|
Category: 似水流年