Python pickle与deepcopy的关系

Python pickle与deepcopy的关系,python,pickle,python-2.x,deep-copy,Python,Pickle,Python 2.x,Deep Copy,pickle和copy.deepcopy之间的关系到底是什么?他们共享什么机制,如何共享 很明显,这两项操作密切相关,并且共享一些机制/协议,但我无法理解细节 我发现了一些(令人困惑的)事情: 如果一个类定义了\ugs]etstate\uu,它们将被调用其实例的deepcopy。一开始这让我很惊讶,因为我认为它们是特定于pickle的,但后来我发现了这一点。但是,没有文档说明深度复制时如何使用\ugs]etstate\uuuuuu(如何使用从\uuuu getstate\uuuuu返回的值,传递

pickle
copy.deepcopy
之间的关系到底是什么?他们共享什么机制,如何共享

很明显,这两项操作密切相关,并且共享一些机制/协议,但我无法理解细节

我发现了一些(令人困惑的)事情:

  • 如果一个类定义了
    \ugs]etstate\uu
    ,它们将被调用其实例的
    deepcopy
    。一开始这让我很惊讶,因为我认为它们是特定于pickle的,但后来我发现了这一点。但是,没有文档说明深度复制时如何使用
    \ugs]etstate\uuuuuu
    (如何使用从
    \uuuu getstate\uuuuu
    返回的值,传递给
    \uuu setstate\uuuuu
    的是什么?)
  • deepcopy
    的一个简单的替代实现是
    pickle.loads(pickle.dumps(obj))
    。但是,这不可能等同于deepcopy,因为如果一个类定义了一个
    \uuu deepcopy\uuu
    操作,那么它将不会使用这个基于pickle的deepcopy实现来调用。(我还偶然发现了一个说法,即deepcopy比pickle更通用,而且有许多类型是可deepcopy的,但不可pickle。)
  • (1) 表示通用性,而(2)表示
    pickle
    deepcopy
    之间的差异

    除此之外,我还发现了两种相互矛盾的说法:

    :pickle、cPickle和copy模块在酸洗/复制这些对象时使用这些功能

    该模块不使用复制注册模块

    一方面,这是
    pickle
    deepcopy
    之间的关系/共性的另一个迹象,另一方面,这也导致了我的困惑


    [我的经验是使用python2.7,但我也希望有人能指出python2和python3在pickle/deepcopy方面的差异]

    好的,我必须阅读这一版本的源代码,但这看起来是一个非常简单的答案。

    copy
    查找一些内置类型,它知道构造函数的外观(在
    \u copy\u dispatch
    字典中注册,当它不知道如何复制基本类型时,它会导入
    copy\u reg.dispatch\u table
    …这是
    pickle
    注册它知道的生成对象新副本的方法的地方。本质上,它是对象类型和“生成新对象的函数”--这个“生成新对象的函数”与您为对象编写
    \uuuu reduce\uuuu
    \uuuu reduce\u ex\uuuuuu
    方法时编写的函数差不多(如果其中一个方法缺失或需要帮助,它将遵循
    \uu setstate\uuuu
    \uu getstate\uuuuuu
    等方法)

    这就是复制,基本上…(还有一些附加条款…)

    deepcopy
    执行与上述相同的操作,但还检查每个对象,确保每个新对象都有一个副本,而不是指针引用。
    deepcopy
    构建自己的
    \u deepcopy\u dispatch
    表(dict)其中,它注册了一些函数,以确保生成的新对象没有指向原始对象的指针引用(可能是使用
    \uuuu reduce\uuuu
    函数生成的,这些函数在
    复制\u reg.分派\u表中注册)


    因此,编写一个
    \uuuuuuuuuuuuuuuuuuuuuuuuuuuuu
    方法(或类似方法)并将其注册到
    copy\ureg
    ,应该使
    copy
    deepcopy
    也能完成它们的任务。

    您不应该被(1)和(2)所迷惑。一般来说,Python试图为缺少的方法提供合理的回退。(例如,定义
    \uuuu getitem\uuuuuuuuu
    就足以拥有一个iterable类,但实现
    \uuuuuuuuuu iter\uuuuuuuuuu
    也可能更有效。类似于
    \uuuuuuuuu add\uuuuuuuuuuuuuuuuuu
    之类的操作,具有可选的
    \uuuuuuu iadd\uuu
    等。)

    \uuuu deepcopy\uuuuu
    deepcopy()
    将要寻找的最专门的方法,但是如果它不存在,回到pickle协议是一件明智的事情。它不会真正调用
    dumps()
    /
    load()
    ,因为它不依赖中间表示形式成为字符串,但它将间接地使用
    \uuuu getstate\uuuu
    \uuu setstate\uuuu
    (通过
    \uu reduce\uuuu
    ),正如您所观察到的那样

    目前,美国

    …复制模块不使用复制注册模块

    但这似乎是(可能2.7分支在这里没有得到足够的关注)


    还要注意的是,这已经非常深入地集成到Python中(至少现在是这样);
    对象
    类本身实现了
    \uuuuuu reduce\uuuuuuu
    (及其版本化的_ex变体),它引用了
    copy\u reg.\uuuu newobj\uuuu
    来创建给定对象派生类的新实例。

    因此看起来像是“copy不使用copy\u reg”“这有点像谎言。它用它来掩盖事实。”哦,我知道Python 2和Python 3之间唯一的区别是
    copy\u reg
    模块被重命名为
    copyreg
    。不,你有点错了。
    deepcopy
    实际上不使用
    \uu getstate\uuuuuu
    \uuu setstate\uuu
    deepcopy
    使用
    \uu deepcopy\uuu
    ,pickle的调度表<代码>\uuuuuuuuuuuuuuuuuu
    \uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu
    可以按顺序调用
    \uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu__getstate和
    更易于使用。(和/或,
    \getinitargs\UUUEngCode>/
    \getnewargs\UUEngCode>)我希望
    
    def copy(x):
        """Shallow copy operation on arbitrary Python objects.
    
        See the module's __doc__ string for more info.
        """
    
        cls = type(x)
    
        copier = _copy_dispatch.get(cls)
        if copier:
            return copier(x)
    
        copier = getattr(cls, "__copy__", None)
        if copier:
            return copier(x)
    
        reductor = dispatch_table.get(cls)
        if reductor:
            rv = reductor(x)
        else:
            reductor = getattr(x, "__reduce_ex__", None)
            if reductor:
                rv = reductor(2)
            else:
                reductor = getattr(x, "__reduce__", None)
                if reductor:
                    rv = reductor()
                else:
                    raise Error("un(shallow)copyable object of type %s" % cls)