pickle
和copy.deepcopy
究竟是什么关系?它们共享哪些机制?如何共享?
很明显,这两者是密切相关的操作,并且共享一些机制/协议(protocol),但我无法深入了解细节。
我发现的一些(令人困惑的)事情:
- 如果一个类定义了
__[gs]etstate__
,它们会在其实例的deepcopy
上被调用。起初这让我很惊讶,因为我认为它们是pickle
特有的,但后来我发现 Classes can use the same interfaces to control copying that they use to control pickling 。但是,没有文档说明 如何__[gs]etstate__
在深度复制时使用(如何使用从__getstate__
返回的值,是什么传递给__setstate__
?) deepcopy
的简单替代实现是pickle.loads(pickle.dumps(obj))
。但是,这不可能等同于 deepcopy'ing,因为如果一个类定义了__deepcopy__
操作,则不会使用基于 pickle 的 deepcopy 实现来调用它。 (我还偶然发现了一种说法,即 deepcopy 比 pickle 更通用,并且有很多类型可以 deepcopy,但不能 pickle。)
(1)表示共性,(2)表示pickle
和deepcopy
的区别。
除此之外,我发现了以下两个相互矛盾的陈述:
copy_reg: The pickle, cPickle, and copy modules use those functions when pickling/copying those objects
和
The copy module does not use the copy_reg registration module
一方面,这表明 pickle
和 deepcopy
之间的关系/共同点,另一方面,这也导致了我的困惑......
[我的经验是使用 python2.7,但我也很感激任何关于 python2 和 python3 之间pickle/deepcopy 差异的指针]
最佳答案
您不应被 (1) 和 (2) 混淆。一般来说,Python 会尝试为缺失的方法包含合理的后备方案。 (例如,定义 __getitem__
以拥有一个可迭代的类就足够了,但同时实现 __iter__
可能更有效。类似 之类的操作__add__
,以及可选的 __iadd__
等)
__deepcopy__
是 deepcopy()
将寻找的最专业的方法,但如果它不存在,回退到 pickle 协议(protocol)是明智之举.它并没有真正调用dumps()
/loads()
,因为它不依赖中间表示为字符串,而是会间接利用__getstate__
和 __setstate__
(通过 __reduce__
),如您所见。
目前,the documentation仍然状态
… The copy module does not use the copy_reg registration module.
但这似乎是 a bug that has been fixed in the meantime (可能是2.7分支在这里没有得到足够的重视)。
还请注意,这已非常深入地集成到 Python 中(至少现在是这样); object
类本身实现了 __reduce__
(及其版本化的 _ex 变体),它引用 copy_reg.__newobj__
来创建给定对象的新实例-派生类。
关于python - pickle 和 deepcopy 的关系,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/22388854/