Je sais que c'est très vieille question, mais je n'ai jamais explicitement vu une solution satisfaisante à cette question autre que la réponse évidente, et le plus probablement correcte, de re-structurer votre code.
Malheureusement, ce n'est pas toujours pratique de faire une telle chose, dans ce cas, comme dernier recours, il est possible de décaper des instances de classes qui sont définies dans une autre classe.
La documentation python pour les __reduce__
function états que vous pouvez retourner
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.
Par conséquent, tout ce que vous avez besoin est un objet qui peut renvoyer une instance de la classe appropriée. Cette classe doit être elle-même picklable (donc, doit vivre au niveau __main__
), et pourrait être aussi simple que:
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()
Tout ce qui reste, est donc de renvoyer les arguments appropriés dans une méthode __reduce__
sur 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__,))
le résultat est une classe qui est imbriqué, mais les instances peuvent être décapés (travaux supplémentaires sont nécessaires pour vider/charger les informations __state__
, mais cela est relativement simple selon la documentation __reduce__
).
Cette même technique (avec de légères modifications de code) peut être appliquée pour les classes profondément imbriquées.
Un exemple bien travaillé:
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
Ma note finale à ce sujet est de se rappeler ce que les autres réponses ont dit:
If you are in a position to do so, consider re-factoring your code to avoid the nested classes in the first place.
hehe, est votre nom d'utilisateur une coïncidence? : p –
Voir aussi la documentation Python pickle: http://docs.python.org/library/pickle.html#the-pickle-protocol – joeforker
En Python 3.4 et supérieur, 'inst = ObjectToPickle(); pickle.dumps (inst, 4) 'fonctionne bien. – Eponymous