<p>我知道这是一个非常古老的问题,但是我从来没有看到过对这个问题的满意的解决方案,除了对代码进行重新构造的明显且最有可能是正确的答案。</p>
<p>不幸的是,这样做并不总是可行的,在这种情况下,作为最后的手段,可以对在另一个类中定义的类的实例进行pickle操作。</p>
<p><a href="http://docs.python.org/library/pickle.html?highlight=__reduce__#object.__reduce__" rel="noreferrer">^{<cd1>} function</a>的python文档声明您可以返回</p>
<blockquote>
<p>A callable object that will be called to create the initial version of the object. The next element of the tuple will provide arguments for this callable.</p>
</blockquote>
<p>因此,您只需要一个对象,它可以返回适当类的实例。这个类必须</strong>本身是可选择的(因此,必须存在于<code>__main__</code>级别),并且可以简单到:</p>
<pre><code>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()
</code></pre>
<p>因此,剩下的就是在FloatType上的<code>__reduce__</code>方法中返回适当的参数:</p>
<pre><code>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__, ))
</code></pre>
<p>结果是一个嵌套的类,但可以对实例进行pickle(需要进一步的工作来转储/加载<code>__state__</code>信息,但根据<code>__reduce__</code>文档,这相对简单)。</p>
<p>同样的技术(稍加代码修改)可以应用于深度嵌套的类。</p>
<p>一个充分发挥作用的例子:</p>
<pre><code>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
</code></pre>
<p>我最后要说的是记住其他答案的意思:</p>
<blockquote>
<p>If you are in a position to do so, consider re-factoring your code to
avoid the nested classes in the first place.</p>
</blockquote>