Python 2.7.3新增了一个功能,允许对动态创建的类进行pickle。请参见
issue 7689:
当前情况下,即使用户通过copy_reg请求不同的pickling机制,通常的pickle机制也无法用于pickle动态创建的类。通过简单地转置两个代码块,附加的补丁使这种自定义成为可能。
和
copy_reg模块存在于处理对象的自定义pickle方案,这正是需要的。然而,检查元类实例的代码来自#494904,它在查看copy_reg分发表之前执行此操作。这些补丁只需重新排列pickle.py和cPickle.c中的这些测试,以便可以为元类实例注册自定义的pickler。
并从
2.7.3 changelog得知:
问题#7689:允许在其元类注册到copy_reg时对动态创建的类进行pickle处理。 Nicolas M. Thiéry和Craig Citro提供了补丁。
Python 2.6唯一的解决方法是将pickle.py模块移植到该版本。您可以尝试将2.7.3 pickle.py模块与2.6捆绑在一起,作为纯Python实现,它应该可以正常工作。
或者,使用monkey-patch方法修改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):
pid = self.persistent_id(obj)
if pid:
self.save_pers(pid)
return
x = self.memo.get(id(obj))
if x:
self.write(self.get(x[0]))
return
t = type(obj)
f = self.dispatch.get(t)
if f:
f(self, obj)
return
reduce = dispatch_table.get(t)
if reduce:
rv = reduce(obj)
else:
try:
issc = issubclass(t, TypeType)
except TypeError:
issc = 0
if issc:
self.save_global(obj)
return
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))
if type(rv) is StringType:
self.save_global(obj, rv)
return
if type(rv) is not TupleType:
raise PicklingError("%s must return string or tuple" % reduce)
l = len(rv)
if not (2 <= l <= 5):
raise PicklingError("Tuple returned by %s must have "
"two to five elements" % reduce)
self.save_reduce(obj=obj, *rv)
Pickler.save = pickler_save
使用上述猴子补丁,你的示例能够在Python 2.6.8上运行:
>>> pickle.dumps(B)
Hey there
'c__main__\nB\np0\n.'
_reduce_a
函数在2.7中被调用,但在2.6中没有被调用。 - Simon Charette