我知道这是一个非常古老的问题,但除了重新构建代码的明显且很可能是正确的答案之外,我从未明确看到此问题的令人满意的解决方案。
不幸的是,做这样的事情并不总是可行的,在这种情况下,作为最后的手段,可以腌制在另一个类中定义的类的实例。
该__reduce__
函数的 python 文档指出您可以返回
将被调用以创建对象的初始版本的可调用对象。元组的下一个元素将为这个可调用对象提供参数。
因此,您所需要的只是一个可以返回相应类的实例的对象。此类本身必须是可腌制的(因此,必须存在于该__main__
级别上),并且可以简单如下:
class _NestedClassGetter(object):
"""
When called with the containing class as the first argument,
and the name of the nested class as the second argument,
returns an instance of the nested class.
"""
def __call__(self, containing_class, class_name):
nested_class = getattr(containing_class, class_name)
# return an instance of a nested_class. Some more intelligence could be
# applied for class construction if necessary.
return nested_class()
因此,剩下的就是__reduce__
在 FloatType 的方法中返回适当的参数:
class WidgetType(object):
class FloatType(object):
def __reduce__(self):
# return a class which can return this class when called with the
# appropriate tuple of arguments
return (_NestedClassGetter(), (WidgetType, self.__class__.__name__, ))
结果是一个嵌套的类,但实例可以腌制(需要进一步的工作来转储/加载信息,但根据文档__state__
,这相对简单)。__reduce__
同样的技术(稍加修改代码)可以应用于深度嵌套的类。
一个完整的例子:
import pickle
class ParentClass(object):
class NestedClass(object):
def __init__(self, var1):
self.var1 = var1
def __reduce__(self):
state = self.__dict__.copy()
return (_NestedClassGetter(),
(ParentClass, self.__class__.__name__, ),
state,
)
class _NestedClassGetter(object):
"""
When called with the containing class as the first argument,
and the name of the nested class as the second argument,
returns an instance of the nested class.
"""
def __call__(self, containing_class, class_name):
nested_class = getattr(containing_class, class_name)
# make an instance of a simple object (this one will do), for which we can change the
# __class__ later on.
nested_instance = _NestedClassGetter()
# set the class of the instance, the __init__ will never be called on the class
# but the original state will be set later on by pickle.
nested_instance.__class__ = nested_class
return nested_instance
if __name__ == '__main__':
orig = ParentClass.NestedClass(var1=['hello', 'world'])
pickle.dump(orig, open('simple.pickle', 'w'))
pickled = pickle.load(open('simple.pickle', 'r'))
print type(pickled)
print pickled.var1
我对此的最后一点是要记住其他答案所说的话:
如果您有能力这样做,请考虑重新分解您的代码以避免首先出现嵌套类。