Есть способ сделать это, но это потребует от вас создать свой собственный класс или стать умным. Вы можете зарегистрировать исходные идентификаторы во время травления и установить функцию отмены засорения для поиска созданного объекта, если он не был засолен, или создать его, если он не был.
У меня есть быстрый пример использования __reduce__
ниже. Но вы, вероятно, должны знать, что это не самая лучшая идея.
Может быть проще использовать библиотеку copyreg
, но вы должны знать, что все, что вы делаете с этой библиотекой, будет влиять на все, что вы маринете все время. Метод __reduce__
будет чище и безопаснее, поскольку вы явно указываете pickle
, какие классы вы ожидаете, чтобы иметь такое поведение, вместо того, чтобы неявно применять их ко всему.
В этой системе есть худшие предостережения. Идентификатор всегда будет меняться между экземплярами Python, поэтому вам нужно сохранить исходный идентификатор во время __init__
(или __new__
, как бы вы это ни делали) и убедиться, что теперь несуществующее значение сохраняется, когда оно вынимается из полки позже , Уникальность идентификатора даже не гарантируется в сеансе Python из-за сборки мусора. Я уверен, что появятся другие причины не делать этого. (Я постараюсь обратиться к ним со своим классом, но я не даю обещаний.)
import uuid
class UniquelyPickledDictionary(dict):
_created_instances = {}
def __init__(self, *args, _uid=None, **kwargs):
super().__init__(*args, **kwargs)
self.uid = _uid
if _uid is None:
self.uid = uuid.uuid4()
UniquelyPickledDictionary._created_instances[self.uid] = self
def __reduce__(self):
return UniquelyPickledDictionary.create, (self.uid,), None, None, list(self.items())
@staticmethod
def create(uid):
if uid in UniquelyPickledDictionary._created_instances:
return UniquelyPickledDictionary._created_instances[uid]
return UniquelyPickledDictionary(_uid=uid)
Библиотека uuid
должна быть более уникальной, чем идентификаторы объектов в долгосрочной перспективе. Я забыл, какие гарантии они имеют, , но я считаю, что это не безопасно для многопроцессорных систем .
Эквивалентная версия, использующая copyreg, может быть сделана для засолки любого класса, но потребует специальной обработки при расщеплении, чтобы гарантировать точки повторения для того же объекта. Чтобы сделать его наиболее общим, необходимо проверить «уже созданный» словарь, чтобы сравнить его со всеми экземплярами. Чтобы сделать его наиболее удобным, к экземпляру необходимо добавить новое значение, что может быть невозможно, если объект использует __slots__
(или в некоторых других случаях).
Я использую 3.6, но я думаю, что это должно работать для любой все еще поддерживаемой версии Python. Он сохранил объект в моем тестировании, с рекурсией (но pickle уже делает это) и множественными расщеплениями.