Sé que esta es una pregunta muy antigua muy, pero nunca he visto explícitamente una solución satisfactoria a esta pregunta que no sea la respuesta obvia, y probablemente correcta, para volver a estructurar el código.
Por desgracia, no siempre es práctico para hacer tal cosa, en cuyo caso, como último recurso, que es posible conservar en vinagre instancias de clases que se definen dentro de otra clase.
La documentación de Python para la __reduce__
function estados que puede volver
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.
Por lo tanto, todo lo que necesita es un objeto que puede devolver una instancia de la clase apropiada. Esta clase debe ser en sí mismo estibables (por lo tanto, debe vivir en el nivel __main__
), y podría ser tan simple como:
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()
Todo lo que queda, por lo tanto, es devolver los argumentos apropiados en un método __reduce__
en 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__,))
el resultado es una clase que se anida pero instancias pueden ser en escabeche (se necesita más trabajo para volcar/cargar la información de __state__
, pero esto es relativamente sencillo como por la documentación __reduce__
).
Esta misma técnica (con ligeras modificaciones de código) se puede aplicar para las clases profundamente anidadas.
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
Mi nota final sobre esto es para recordar lo que las otras respuestas han dicho::
Un ejemplo práctico totalmente
If you are in a position to do so, consider re-factoring your code to avoid the nested classes in the first place.
jeje, es su nombre de usuario una coincidencia? : p –
Vea también la documentación de picking de Python: http://docs.python.org/library/pickle.html#the-pickle-protocol – joeforker
En Python 3.4 y superior, 'inst = ObjectToPickle(); pickle.dumps (inst, 4) 'funciona bien. – Eponymous