您可以决定并实现任何以前不可提取的类型如何被腌制和解封:请参阅标准库模块copy_reg(copyreg
在 Python 3.* 中重命名为)。
本质上,您需要提供一个函数,在给定类型实例的情况下,将其简化为一个元组——使用与 reduce 特殊方法相同的协议(除了 reduce 特殊方法不带参数,因为提供时直接调用它在对象上,而您提供的函数将对象作为唯一的参数)。
通常,您返回的元组有 2 个项目:一个可调用项和一个要传递给它的参数元组。可调用对象必须注册为“安全构造函数”或等效地具有具有__safe_for_unpickling__
真值的属性。这些项目将被腌制,并且在取消腌制时,将使用给定的参数调用可调用对象,并且必须返回未选中的对象。
例如,假设您只想按名称腌制模块,因此取消腌制它们只是意味着重新导入它们(即,为简单起见,假设您不关心动态修改的模块、嵌套包等,只是简单的顶级模块)。然后:
>>> import sys, pickle, copy_reg
>>> def savemodule(module):
... return __import__, (module.__name__,)
...
>>> copy_reg.pickle(type(sys), savemodule)
>>> s = pickle.dumps(sys)
>>> s
"c__builtin__\n__import__\np0\n(S'sys'\np1\ntp2\nRp3\n."
>>> z = pickle.loads(s)
>>> z
<module 'sys' (built-in)>
我使用的是老式的 ASCII 形式的 pickle,因此s
包含 pickle 的字符串很容易检查:它指示 unpickling 调用内置的导入函数,并将字符串sys
作为其唯一参数。并且z
表明这确实根据需要将内置sys
模块作为 unpickling 的结果返回给我们。
现在,您必须让事情变得更复杂一些__import__
(您必须处理保存和恢复动态更改、导航嵌套命名空间等),因此您还必须调用copy_reg.constructor
(作为参数传递你自己的函数来执行这项工作)在你copy_reg
返回你的其他函数的模块保存函数之前(并且,如果在单独的运行中,也在你解开你使用所述函数制作的那些泡菜之前)。但我希望这个简单的案例有助于表明它真的没有什么“本质上”复杂的!-)