status

草稿

清风 & Liz; 100%

PCS210 pickle

概述

pickle模块可以实现任意的Python对象的序列化.这些序列化后的对象可以被传输或存储,也可以重构为一个和原先对象具有相同特征的新对象。但在实际项目中为了提高序列化和反序列化的速度,可以改用cPickle模块.pickle的文档清晰的表明它不提供安全保证。所以慎用pickle来作为内部进程通信或者数据存储,也不要相信那些你不能验证安全性的数据。

使用

第一个pickle示例是将一个数据结构编码为一个字符串,然后将其输出到控制台。

   1 try:
   2    import cPickle as pickle
   3 except:
   4    import pickle
   5 import pprint

首先尝试导入cPickle,并指定别名为"pickle"。如果因为某种原因导入pickle失败,则导入由Python实现的pickle模块。这样,如果cPickle可用则速度会快点,但如果不可用,也会有正确的实现。接下来,定义一个完全由基本类型组成的数据结构。

   1 data = [ { 'a':'A', 'b':2, 'c':3.0 } ]
   2 print 'DATA:',
   3 pprint.pprint(data)

可以使用pickle.dumps()来创建数据值的字符串表示。

   1 data_string = pickle.dumps(data)
   2 print 'PICKLE:', data_string

可以看到结果如下:

~$ python pcs-201-1.py
DATA:[{'a': 'A', 'b': 2, 'c': 3.0}]
PICKLE: (lp1
(dp2
S'a'
S'A'
sS'c'
F3
sS'b'
I2
sa.

一旦数据被序列化,就可以把他写入到文件、socket、管道等等中。之后你可以读取这个文件,读取这些数据来构造具有相同值的新对象。

   1 # -*- coding: utf-8 -*-
   2 data1 = [ { 'a':'A', 'b':2, 'c':3.0 } ]
   3 print 'BEFORE:',
   4 pprint.pprint(data1)
   5 
   6 data1_string = pickle.dumps(data1)
   7 
   8 data2 = pickle.loads(data1_string)
   9 print 'AFTER:',
  10 pprint.pprint(data2)
  11 
  12 print 'SAME?:', (data1 is data2)
  13 print 'EQUAL?:', (data1 == data2)

新构造的对象等于原来的对象,但他们又不是相同的对象。

~$ python pcs-201-2.py
BEFORE:[{'a': 'A', 'b': 2, 'c': 3.0}]
AFTER:[{'a': 'A', 'b': 2, 'c': 3.0}]
SAME?: False
EQUAL?: True

在处理自定义类时,应该保证这些被序列化的类会在进程名空间出现 。只有数据实例才能被序列化,而不能是定义的类。在反序列化时,类的名字被用于寻找构造器以便创建新对象。接下来这个例子,是将一个类实例写入到文件中:

   1 # -*- coding: utf-8 -*-
   2 try:
   3    import cPickle as pickle
   4 except:
   5    import pickle
   6 import sys
   7 
   8 class SimpleObject(object):
   9 
  10    def __init__(self, name):
  11        self.name = name
  12        l = list(name)
  13        l.reverse()
  14        self.name_backwards = ''.join(l)
  15        return
  16 
  17 if __name__ == '__main__':
  18    data = []
  19    data.append(SimpleObject('pickle'))
  20    data.append(SimpleObject('cPickle'))
  21    data.append(SimpleObject('last'))
  22 
  23    try:
  24        filename = sys.argv[1]
  25    except IndexError:
  26        raise RuntimeError('Please specify a filename as an argument to %s' % sys.argv[0])
  27 
  28    out_s = open(filename, 'wb')
  29    try:
  30        # 写入到流中
  31        for o in data:
  32            print 'WRITING: %s (%s)' % (o.name, o.name_backwards)
  33            pickle.dump(o, out_s)
  34    finally:
  35        out_s.close()

当运行这个脚本时,它会创建名为命令行中输入参数的文件:

~$ python pcs-201-3.py test.dat
WRITING: pickle (elkcip)
WRITING: cPickle (elkciPc)
WRITING: last (tsal)

一个简单的尝试是将刚才的序列化对象装载进来,如下:

   1 # -*- coding: utf-8 -*-
   2 try:
   3    import cPickle as pickle
   4 except:
   5    import pickle
   6 import pprint
   7 from StringIO import StringIO
   8 import sys
   9 #注意:需要导入自定义类
  10 from pcs-201-3 import SimpleObject
  11 
  12 try:
  13    filename = sys.argv[1]
  14 except IndexError:
  15    raise RuntimeError('Please specify a filename as an argument to %s' % sys.argv[0])
  16 
  17 in_s = open(filename, 'rb')
  18 try:
  19    # 读取数据
  20    while True:
  21        try:
  22            o = pickle.load(in_s)
  23        except EOFError:
  24            break
  25        else:
  26            print 'READ: %s (%s)' % (o.name, o.name_backwards)
  27 finally:
  28    in_s.close()

运行这个脚本,可以看到:

~$ python pcs-201-4.py test.dat
READ: pickle (elkcip)
READ: cPickle (elkciPc)
READ: last (tsal)