Pydantic不能pickle私有属性



我试图为我的模型设置一个私有属性(不能pickle):

from threading import Lock
from pydantic import BaseModel
class MyModel(BaseModel):
class Config:
underscore_attrs_are_private = True
_lock: Lock = Lock() # This cannot be copied
x = MyModel()

但是这会产生一个错误:

Traceback (most recent call last):
File ".../example.py", line 9, in <module>
x = MyModel()
File "pydanticmain.py", line 349, in pydantic.main.BaseModel.__init__
File "pydanticmain.py", line 419, in pydantic.main.BaseModel._init_private_attributes
File "pydanticfields.py", line 1180, in pydantic.fields.ModelPrivateAttr.get_default
File "pydanticutils.py", line 657, in pydantic.utils.smart_deepcopy
File "...libcopy.py", line 161, in deepcopy
rv = reductor(4)
TypeError: cannot pickle '_thread.lock' object

似乎它失败了,因为Lock不能被pickle(或复制)。此外,Pydantic似乎出于某种原因试图复制私有属性。我看了看文档,找不到一个模型属性来覆盖这个。同时,配置arbitrary_types_allowedcopy_on_model_validation也没有影响。我也尝试使用PrivateAttr(default=Lock()),但没有帮助。

有趣的是,如果属性不是私有的(通过在Config中设置underscore_attrs_are_private = False),该示例也可以工作。

我希望这个属性是私有的。如何设置不能pickle到Pydantic Model的私有属性?

经过一番调查,我自己找到了答案。这似乎可以使用default_factory:

来解决。
from threading import Lock
from pydantic import BaseModel, PrivateAttr
class MyModel(BaseModel):
class Config:
underscore_attrs_are_private = True

_lock = PrivateAttr(default_factory=Lock)

x = MyModel()

此外,似乎复制只在BaseModelinit中完成。还可以稍后设置该属性:

from threading import Lock
from pydantic import BaseModel, PrivateAttr
class MyModel(BaseModel):
class Config:
underscore_attrs_are_private = True

_lock: Lock

def __init__(self, **kwargs):
super().__init__(**kwargs)
self._lock = Lock()

x = MyModel()