これは非常に古い質問であることは知っていますが、コードを再構築するための明白でおそらく正しい答え以外に、この質問に対する満足のいく解決策を明示的に見たことはありません。
残念ながら、そのようなことを行うことは必ずしも実用的ではありません。その場合、最後の手段として、別のクラス内で定義されているクラスのインスタンスをピクルスにすることができます。
__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
これに関する私の最後の注意は、他の答えが言ったことを覚えておくことです:
そうする立場にある場合は、そもそもネストされたクラスを回避するためにコードをリファクタリングすることを検討してください。