Python 2.7.3 添加了一个新功能,允许对动态创建的类进行腌制。请参阅问题 7689:
目前,即使用户通过 copy_reg 请求不同的 pickle 机制,也无法使用通常的 pickle 机制来 pickle 动态创建的类。附加的补丁通过简单地转置两个代码块使这种定制成为可能。
和
copy_reg 模块用于处理对象的自定义酸洗,这正是这里需要的。但是,#494904中检查元类实例的代码*就在*之前*它查看 copy_reg 调度表。这些补丁只是在 pickle.py 和 cPickle.c 中重新排序这些测试,以便可以为元类的实例注册一个自定义pickler。
从2.7.3 更新日志:
问题 #7689:当动态创建的类使用 copy_reg 注册时,允许对动态创建的类进行酸洗。Nicolas M. Thiéry 和 Craig Citro 的补丁。
对于 Python 2.6,解决此问题的唯一方法是将pickle.py
模块移植到该版本。您可以尝试将 2.7.3pickle.py
模块与 2.6 捆绑在一起,作为纯 Python 实现,它应该可以正常工作。
或者,猴子修补pickle.Pickler.save
方法:
from copy_reg import dispatch_table
from types import TypeType, StringType, TupleType
from pickle import Pickler, PicklingError
def pickler_save(self, obj):
# Check for persistent id (defined by a subclass)
pid = self.persistent_id(obj)
if pid:
self.save_pers(pid)
return
# Check the memo
x = self.memo.get(id(obj))
if x:
self.write(self.get(x[0]))
return
# Check the type dispatch table
t = type(obj)
f = self.dispatch.get(t)
if f:
f(self, obj) # Call unbound method with explicit self
return
# Check copy_reg.dispatch_table
reduce = dispatch_table.get(t)
if reduce:
rv = reduce(obj)
else:
# Check for a class with a custom metaclass; treat as regular class
try:
issc = issubclass(t, TypeType)
except TypeError: # t is not a class (old Boost; see SF #502085)
issc = 0
if issc:
self.save_global(obj)
return
# Check for a __reduce_ex__ method, fall back to __reduce__
reduce = getattr(obj, "__reduce_ex__", None)
if reduce:
rv = reduce(self.proto)
else:
reduce = getattr(obj, "__reduce__", None)
if reduce:
rv = reduce()
else:
raise PicklingError("Can't pickle %r object: %r" %
(t.__name__, obj))
# Check for string returned by reduce(), meaning "save as global"
if type(rv) is StringType:
self.save_global(obj, rv)
return
# Assert that reduce() returned a tuple
if type(rv) is not TupleType:
raise PicklingError("%s must return string or tuple" % reduce)
# Assert that it returned an appropriately sized tuple
l = len(rv)
if not (2 <= l <= 5):
raise PicklingError("Tuple returned by %s must have "
"two to five elements" % reduce)
# Save the reduce() output and finally memoize the object
self.save_reduce(obj=obj, *rv)
Pickler.save = pickler_save
使用上面的猴子补丁,您的示例适用于 Python 2.6.8:
>>> pickle.dumps(B)
Hey there
'c__main__\nB\np0\n.'