Стабильная сериализация Python (например.нет проблем с перемещением модуля рассола)
-
19-09-2019 - |
Вопрос
Я рассматриваю возможность использования Количества определить число вместе с его единицей.Это значение, скорее всего, придется сохранить на диске.Как вы, наверное, знаете, у маринования есть одна серьезная проблема:если вы переместите модуль, расконсервация не сможет разрешить класс, и вы не сможете расконсервировать информацию.Есть обходные пути для такого поведения, но это действительно обходные пути.
Решением, которое я придумал для этой проблемы, было бы создание строки, уникально кодирующей данную единицу измерения.Получив эту кодировку с диска, вы передаете ее фабричному методу модуля Quantities, который декодирует ее в соответствующий экземпляр единицы измерения.Преимущество в том, что даже если вы переместите модуль, все будет работать, пока вы передаете токен волшебной строки фабричному методу.
Это известная концепция?
Решение
Похоже на применение Первого принципа Уиллера: «все проблемы в информатике могут быть решены с помощью другого уровня косвенности» (Второй принцип добавляет: «но это обычно создает еще одну проблему» ;-).По сути, вам нужно косвенно идентифицировать тип -- тип сущности подойдет для подходов, подобных травлению (вы можете изучить источники pickle.py
и copy_reg.py
для всех мелких деталей последнего).
В частности, я считаю, что то, что вы хотите сделать, это подкласс pickle.Pickler
и переопределить save_inst
метод.Где в текущей версии написано:
if self.bin:
save(cls)
for arg in args:
save(arg)
write(OBJ)
else:
for arg in args:
save(arg)
write(INST + cls.__module__ + '\n' + cls.__name__ + '\n')
вы хотите написать что-то другое, а не только модуль и имя класса — какой-то уникальный идентификатор (состоящий из двух строк) для класса, который, вероятно, хранится в вашем собственном реестре или реестрах;и аналогично для save_global
метод.
Это еще проще для вашего подкласса Unpickler
, поскольку _instantiate
часть уже вынесена в отдельный метод:вам нужно только переопределить find_class
, который:
def find_class(self, module, name):
# Subclasses may override this
__import__(module)
mod = sys.modules[module]
klass = getattr(mod, name)
return klass
он должен принимать две строки и возвращать объект класса;вы можете сделать это снова через свои реестры.
Как всегда, когда речь идет о реестрах, вам нужно подумать о том, как обеспечить регистрацию всех интересующих объектов (классов) и т. д. и т. п.Одна из популярных стратегий здесь — оставить травление в покое, но обеспечить, чтобы все перемещения классов, переименования модулей и т. д. записывались где-нибудь на постоянной основе;Таким образом, всю работу может выполнять только разборщик подклассов, и удобнее всего делать все это в переопределенном классе. find_class
-- обход всех вопросов регистрации.Я так понимаю, вы считаете это «обходным решением», но мне это кажется просто чрезвычайно простой, мощной и удобной реализацией концепции «еще одного уровня косвенности», которая позволяет избежать проблемы «еще одной проблемы» ;-).