我知道,如果可变对象被放置在缺省值中,那么Pydtic会为我们创建的"every new instances"创建可变对象的深度副本.

它适用于我的lst字段,但不适用于我的自定义对象item.(__deepcopy__的代码取自here)

from copy import deepcopy
from typing import Self

from pydantic import BaseModel, ConfigDict


class Spam:
    def __init__(self) -> None:
        self.names = ["hi"]

    def __deepcopy__(self, memo: dict) -> Self:
        print("deepcopy called")
        cls = self.__class__
        result = cls.__new__(cls)
        memo[id(self)] = result
        for k, v in self.__dict__.items():
            setattr(result, k, deepcopy(v, memo))
        return result


class Person(BaseModel):
    model_config = ConfigDict(arbitrary_types_allowed=True)

    item: Spam = Spam()
    lst: list = []


print("-----------------------------------")

obj1 = Person()
obj2 = Person()

obj1.lst.append(10)
obj1.item.names.append("bye")

print(obj1.lst)
print(obj1.item.names)
print(obj2.lst)
print(obj2.item.names)
print(id(obj1.item) == id(obj2.item))

输出:

deepcopy called
-----------------------------------
[10]
['hi', 'bye']
[]
['hi', 'bye']
True

我在创建类之后和任何实例化之前打印了虚线,只是为了表明我的对象的深度副本确实发生在类创建过程中,这与documentation:

在创建模型的每个实例时,PYDANIC将深度复制默认值

我是不是错过了什么?

推荐答案

它只适用于不可哈希的对象,但根据Python文档

作为用户定义类的实例的对象可通过 默认设置

https://docs.python.org/3/glossary.html#term-hashable

(我也大吃一惊)

所以,你可以用default_factory来实现你的目标:

from copy import deepcopy

from pydantic import BaseModel, ConfigDict, Field


class Spam:
    def __init__(self) -> None:
        self.names = ["hi"]

    # def __deepcopy__(self, memo: dict):
    #     print("deepcopy called")
    #     cls = self.__class__
    #     result = cls.__new__(cls)
    #     memo[id(self)] = result
    #     for k, v in self.__dict__.items():
    #         setattr(result, k, deepcopy(v, memo))
    #     return result


class Person(BaseModel):
    model_config = ConfigDict(arbitrary_types_allowed=True)

    item: Spam = Field(default_factory=Spam)
    lst: list = []


print("-----------------------------------")

obj1 = Person()
obj2 = Person()

obj1.lst.append(10)
obj1.item.names.append("bye")

print(obj1.lst)
print(obj1.item.names)
print(obj2.lst)
print(obj2.item.names)
print(id(obj1.item) == id(obj2.item))

Python相关问答推荐

将numpy数组存储在原始二进制文件中

Pystata:从Python并行运行stata实例

SQLGory-file包FilField不允许提供自定义文件名,自动将文件保存为未命名

需要计算60,000个坐标之间的距离

追溯(最近最后一次调用):文件C:\Users\Diplom/PycharmProject\Yolo01\Roboflow-4.py,第4行,在模块导入roboflow中

将数据框架与导入的Excel文件一起使用

从spaCy的句子中提取日期

提取相关行的最快方法—pandas

合并帧,但不按合并键排序

将scipy. sparse矩阵直接保存为常规txt文件

使用BeautifulSoup抓取所有链接

重置PD帧中的值

基于Scipy插值法的三次样条系数

递归函数修饰器

mdates定位器在图表中显示不存在的时间间隔

如果服务器设置为不侦听创建,则QWebSocket客户端不连接到QWebSocketServer;如果服务器稍后开始侦听,则不连接

将像素信息写入文件并读取该文件

极点用特定值替换前n行

为什么在不先将包作为模块导入的情况下相对导入不起作用

PYODBC错误(SQL包含-26272个参数标记,但提供了235872个参数,HY 000)