Я знаю, что это очень старый вопрос, но я никогда не видел явно удовлетворительного решения этого вопроса, кроме очевидного и, скорее всего, правильного ответа для реструктуризации вашего кода.
К сожалению, не всегда практично делать такие вещи, и в этом случае в качестве крайней меры можно выбирать объекты классов, которые определены внутри другого класса.
Документация Python для функции __reduce__
гласит, что вы можете вернуть
Вызываемый объект, который будет вызываться для создания начальной версии объекта. Следующий элемент кортежа предоставит аргументы для этого вызываемого элемента.
Следовательно, все, что вам нужно, это объект, который может возвращать экземпляр соответствующего класса. Этот класс должен сам по себе быть отборным (следовательно, должен жить на уровне __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
Мое последнее замечание: вспомнить, что говорили другие ответы:
Если вы в состоянии сделать это, рассмотрите возможность перефакторинга вашего кода в
Во-первых, избегайте вложенных классов.