在Python中对弱引用进行序列化
我对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
序列化,也可以把 dict
和 list
序列化。简单来说,关键在于这些对象里面包含了什么。如果 dict
或 list
里面有一些不能被序列化的东西,那么序列化就会失败。如果你想序列化一个 weakref
,你需要用 dill
而不是 pickle
。dill
是对 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>