linux编程之序列化存储python对象(下)

  相等,但并不总是相同

  正如在上一个示例所暗示的,只有在这些对象引用内存中同一个对象时,它们才是相同的。在 pickle 情形中,每个对象被恢复到一个与原来对象相等的对象,但不是同一个对象。换句话说,每个 pickle 都是原来对象的一个副本:

  >>> j = [1, 2, 3]
  >>> k = j
  >>> k is j
  1
  >>> x = pickle.dumps(k)
  >>> y = pickle.loads(x)
  >>> y
  [1, 2, 3]
  >>> y == k
  1
  >>> y is k
  0
  >>> y is j
  0
  >>> k is j
  1

  清单 8. 作为原来对象副本的被恢复的对象

  同时,我们看到 python 能够维护对象之间的引用,这些对象是作为一个单元进行 pickle 的。然而,我们还看到分别调用 dump() 会使 python 无法维护对在该单元外部进行 pickle 的对象的引用。相反,python 复制了被引用对象,并将副本和被 pickle 的对象存储在一起。对于 pickle 和恢复单个对象层次结构的应用程序,这是没有问题的。但要意识到还有其它情形。

  值得指出的是,有一个选项确实允许分别 pickle 对象,并维护相互之间的引用,只要这些对象都是 pickle 到同一文件即可。pickle 和 cpickle 模块提供了一个 pickler(与此相对应是 unpickler),它能够跟踪已经被 pickle 的对象。通过使用这个 pickler,将会通过引用而不是通过值来 pickle 共享和循环引用:

  >>> f = file(‘temp.pkl’, ‘w’)
  >>> pickler = pickle.pickler(f)
  >>> pickler.dump(a)
  
  >>> pickler.dump(b)
  
  >>> f.close()
  >>> f = file(‘temp.pkl’, ‘r’)
  >>> unpickler = pickle.unpickler(f)
  >>> c = unpickler.load()
  >>> d = unpickler.load()
  >>> c[2]
  [3, 4, [1, 2, […]]]
  >>> d[2]
  [1, 2, [3, 4, […]]]
  >>> c[2] is d
  1
  >>> d[2] is c
  1

  清单 9. 维护分别 pickle 的对象间的引用

  不可 pickle 的对象

  一些对象类型是不可 pickle 的。例如,python 不能 pickle 文件对象(或者任何带有对文件对象引用的对象),因为 python 在 unpickle 时不能保证它可以重建该文件的状态(另一个示例比较难懂,在这类文章中不值得提出来)。试图 pickle 文件对象会导致以下错误:

  >>> f = file(‘temp.pkl’, ‘w’)
  >>> p = pickle.dumps(f)
  traceback (most recent call last):
  file “”, line 1, in ?
  file “/usr/lib/python2.2/copy_reg.py”, line 57, in _reduce
  raise typeerror, “can’t pickle %s objects” % base.__name__
  typeerror: can’t pickle file objects

  清单 10. 试图 pickle 文件对象的结果