python pickle.dumps 断言错误

4 投票
1 回答
2144 浏览
提问于 2025-04-16 08:27

我正在尝试把一个包含两个列表的类实例进行序列化,这两个列表里又有其他实例。这些实例之间有一些属性是互相引用的。下面是这些类的代码。

import pickle
from copy import copy

class Graph:
    def __init__(self):
        self.vertices = {}
        self.edges = set()
    def __repr__(self):
        return "\n".join(map(str, sorted(self.vertices, key=lambda v:v.id)))

class Edge:
    def __init__(self, vfrom, vto):
        self.vfrom = vfrom
        self.vto = vto
    def __hash__(self):
        return hash((self.vto, self.vfrom))
    def __repr__(self):
        return str(self.vto.id)
    def __getstate__(self):
        vfrom = copy(self.vfrom)
        vfrom.del_outgoing(self)
        vto = copy(self.vto)
        vto.del_incoming(self)
        self.__dict__.update({"vfrom":vfrom, "vto":vto, })
        return self.__dict__
    def __setstate__(self, state):
        self.__dict__.update(state)
        self.__dict__["vfrom"].add_outgoing(self)
        self.__dict__["vto"].add_incoming(self)

class Vertex:
    def __init__(self, id):
        self.id = id
        self.incoming = set()
        self.outgoing = set()
    def __repr__(self):
        return "Vertex %d -> %s"%(self.id, ", ".join(map(str, self.outgoing)))
    def __hash__(self):
        return hash(self.id)
    def add_incoming(self, edge):
        if not edge in self.incoming:
            self.incoming.add(edge)
    def add_outgoing(self, edge):
        if not edge in self.outgoing:
            self.outgoing.add(edge)
    def del_incoming(self, edge):
        self.incoming.discard(edge)
    def del_outgoing(self, edge):
        self.outgoing.discard(edge)

当我尝试序列化一个简单的图形时,出现了一个断言错误。

>>> v0 = Vertex(0)
>>> v1 = Vertex(1)
>>> e0to1 = Edge(v0, v1)
>>> v0.add_outgoing(e0to1)
>>> v1.add_incoming(e0to1)
>>> g = Graph()
>>> g.vertices[v0] = v0
>>> g.vertices[v1] = v1
>>> g.edges.add(e0to1)
>>> g.edges.add(e0to1)
>>> v2 = Vertex(2)
>>> e0to2 = Edge(v0, v2)
>>> v0.add_outgoing(e0to2)
>>> v2.add_incoming(e0to2)
>>> g.vertices[v2] = v2
>>> g.edges.add(e0to2)
>>> 
>>> print g
Vertex 0 -> 2, 1
Vertex 1 -> 
Vertex 2 -> 
>>> p = pickle.dumps(g)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/usr/lib/python2.6/pickle.py", line 1366, in dumps
    Pickler(file, protocol).dump(obj)
  File "/usr/lib/python2.6/pickle.py", line 224, in dump
    self.save(obj)
  File "/usr/lib/python2.6/pickle.py", line 286, in save
    f(self, obj) # Call unbound method with explicit self
  File "/usr/lib/python2.6/pickle.py", line 725, in save_inst
    save(stuff)
  File "/usr/lib/python2.6/pickle.py", line 286, in save
    f(self, obj) # Call unbound method with explicit self
  File "/usr/lib/python2.6/pickle.py", line 649, in save_dict
    self._batch_setitems(obj.iteritems())
  File "/usr/lib/python2.6/pickle.py", line 663, in _batch_setitems
    save(v)
  File "/usr/lib/python2.6/pickle.py", line 331, in save
    self.save_reduce(obj=obj, *rv)
  File "/usr/lib/python2.6/pickle.py", line 401, in save_reduce
    save(args)
  File "/usr/lib/python2.6/pickle.py", line 286, in save
    f(self, obj) # Call unbound method with explicit self
  File "/usr/lib/python2.6/pickle.py", line 562, in save_tuple
    save(element)
  File "/usr/lib/python2.6/pickle.py", line 286, in save
    f(self, obj) # Call unbound method with explicit self
  File "/usr/lib/python2.6/pickle.py", line 600, in save_list
    self._batch_appends(iter(obj))
  File "/usr/lib/python2.6/pickle.py", line 615, in _batch_appends
    save(x)
  File "/usr/lib/python2.6/pickle.py", line 286, in save
    f(self, obj) # Call unbound method with explicit self
  File "/usr/lib/python2.6/pickle.py", line 725, in save_inst
    save(stuff)
  File "/usr/lib/python2.6/pickle.py", line 286, in save
    f(self, obj) # Call unbound method with explicit self
  File "/usr/lib/python2.6/pickle.py", line 649, in save_dict
    self._batch_setitems(obj.iteritems())
  File "/usr/lib/python2.6/pickle.py", line 663, in _batch_setitems
    save(v)
  File "/usr/lib/python2.6/pickle.py", line 286, in save
    f(self, obj) # Call unbound method with explicit self
  File "/usr/lib/python2.6/pickle.py", line 725, in save_inst
    save(stuff)
  File "/usr/lib/python2.6/pickle.py", line 286, in save
    f(self, obj) # Call unbound method with explicit self
  File "/usr/lib/python2.6/pickle.py", line 649, in save_dict
    self._batch_setitems(obj.iteritems())
  File "/usr/lib/python2.6/pickle.py", line 663, in _batch_setitems
    save(v)
  File "/usr/lib/python2.6/pickle.py", line 331, in save
    self.save_reduce(obj=obj, *rv)
  File "/usr/lib/python2.6/pickle.py", line 405, in save_reduce
    self.memoize(obj)
  File "/usr/lib/python2.6/pickle.py", line 244, in memoize
    assert id(obj) not in self.memo
AssertionError

当我去掉v2的时候,这个问题就解决了。

>>> v0 = Vertex(0)
>>> v1 = Vertex(1)
>>> e0to1 = Edge(v0, v1)
>>> v0.outgoing.add(e0to1)
>>> v1.incoming.add(e0to1)
>>> g = Graph()
>>> g.vertices[v0] = v0
>>> g.vertices[v1] = v1
>>> g.edges.add(e0to1)
>>> g.edges.add(e0to1)
>>> import cPickle as pickle
>>> p = pickle.dumps(g)
>>> print pickle.loads(p)
Vertex 0 -> 1
Vertex 1 -> 

你有什么想法吗?

1 个回答

0

有一些数据是旧版的pickle协议处理不了的。为了解决这个问题,你可以使用pickle.HIGHEST_PROTOCOL。

>>> p = pickle.dumps(g)
  File "/usr/lib/python2.6/pickle.py", line 244, in memoize
    assert id(obj) not in self.memo
AssertionError:
>>> p = pickle.dumps(g, pickle.HIGHEST_PROTOCOL)
>>> # No problem!

撰写回答