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。)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)