在Python中对弱引用进行序列化

18 投票
2 回答
53464 浏览
提问于 2025-04-18 06:29

我对Python还很陌生,对“序列化”(pickling)更是新手。我有一个类叫做 Vertex(ScatterLayout),里面有一个 __getnewargs__() 方法:

def __getnewargs__(self):
    return (self.pos, self.size, self.idea.text)

我的理解是,这个方法会让序列化过程使用 __getnewargs__() 返回的内容,而不是对象的字典。

这个序列化是在另一个类 MindMapApp(App) 的一个方法中调用的:

def save(self):
    vertices = self.mindmap.get_vertices()
    edges = self.mindmap.get_edges()

    output = open('mindmap.pkl', 'wb')

    #pickle.dump(edges, output, pickle.HIGHEST_PROTOCOL)
    pickle.dump(vertices, output, pickle.HIGHEST_PROTOCOL)

    output.close()

当我调用 save() 方法时,出现了以下错误:

pickle.PicklingError: Can't pickle <type 'weakref'>: it's not found as __builtin__.weakref

我缺少了什么,或者说我哪里理解错了?我也尝试过实现 __getstate__()__setstate__(state) 这两个方法的组合,但结果还是一样。

2 个回答

3

我通过在 __getstate____setstate__ 之间切换使用弱引用和强引用来解决这个问题:

class DBObject(object):
    def __getstate__(self):
        s = self.__dict__.copy()
        s['_db'] = s['_db']()
        return s

    def __setstate__(self, state):
        self.__dict__ = state.copy()
        self.__dict__['_db'] = weakref.ref(self.__dict__['_db'])
17

你当然可以把一个 weakref 序列化,也可以把 dictlist 序列化。简单来说,关键在于这些对象里面包含了什么。如果 dictlist 里面有一些不能被序列化的东西,那么序列化就会失败。如果你想序列化一个 weakref,你需要用 dill 而不是 pickledill 是对 pickle 的扩展,它可以处理一些用 pickle 不能处理的对象。不过要注意,使用 dill 之后,反序列化的 weakref 会变成无效的引用。

>>> import dill
>>> import weakref
>>> dill.loads(dill.dumps(weakref.WeakKeyDictionary()))
<WeakKeyDictionary at 4528979192>
>>> dill.loads(dill.dumps(weakref.WeakValueDictionary()))
<WeakValueDictionary at 4528976888>
>>> class _class:
...   def _method(self):
...     pass
... 
>>> _instance = _class()
>>> dill.loads(dill.dumps(weakref.ref(_instance)))
<weakref at 0x10d748940; dead>
>>> dill.loads(dill.dumps(weakref.ref(_class())))
<weakref at 0x10e246a48; dead>
>>> dill.loads(dill.dumps(weakref.proxy(_instance)))
<weakproxy at 0x10e246b50 to NoneType at 0x10d481598>
>>> dill.loads(dill.dumps(weakref.proxy(_class())))
<weakproxy at 0x10e246ba8 to NoneType at 0x10d481598>

撰写回答