首页 > Python基础教程 >
-
Python3标准库:pickle对象串行化
作者:@小灰灰
本文为作者原创,转载请注明出处:https://www.cnblogs.com/liuhui0308/p/12504654.html
1. pickle对象串行化
pickle模块实现了一个算法可以将任意的Python对象转换为一系列字节。这个过程也被称为串行化对象。可以传输或存储表示对象的字节流,然后再重新构造来创建有相同性质的新对象。
1.1 编码和解码字符串中的数据
第一个例子使用dumps()将一个数据结构编码为一个字符串,然后把这个字符串打印到控制台。它使用了一个完全由内置类型构成的数据结构。任何类的实例都可以pickled,如后面的例子所示。
- import pickle
- import pprint
- data = [{'a': 'A', 'b': 2, 'c': 3.0}]
- print('DATA:', end=' ')
- pprint.pprint(data)
- data_string = pickle.dumps(data)
- print('PICKLE: {!r}'.format(data_string))
默认的,pickle将以一种二进制格式写入,在Python 3程序之间共享时这种格式兼容性最好。
数据串行化后,可以写到一个文件、套接字、管道或者其他位置。之后可以读取这个文件,将数据解除pickled,以便用同样的值构造一个新对象。
- import pickle
- import pprint
- data1 = [{'a': 'A', 'b': 2, 'c': 3.0}]
- print('BEFORE: ', end=' ')
- pprint.pprint(data1)
- data1_string = pickle.dumps(data1)
- data2 = pickle.loads(data1_string)
- print('AFTER : ', end=' ')
- pprint.pprint(data2)
- print('SAME? :', (data1 is data2))
- print('EQUAL?:', (data1 == data2))
新构造的对象等于原来的对象,但并不是同一个对象。
1.2 处理流
除了dumps()和loads(),pickle还提供了一些便利函数来处理类似文件的流。可以向一个流写多个对象,然后从流读取这些对象,而无须事先知道要写多少个对象或者这些对象多大。
- import io
- import pickle
- class SimpleObject:
- def __init__(self, name):
- self.name = name
- self.name_backwards = name[::-1]
- return
- data = []
- data.append(SimpleObject('pickle'))
- data.append(SimpleObject('preserve'))
- data.append(SimpleObject('last'))
- # Simulate a file.
- out_s = io.BytesIO()
- # Write to the stream
- for o in data:
- print('WRITING : {} ({})'.format(o.name, o.name_backwards))
- pickle.dump(o, out_s)
- out_s.flush()
- # Set up a read-able stream
- in_s = io.BytesIO(out_s.getvalue())
- # Read the data
- while True:
- try:
- o = pickle.load(in_s)
- except EOFError:
- break
- else:
- print('READ : {} ({})'.format(
- o.name, o.name_backwards))
这个例子使用两个BytesIO缓冲区来模拟流。第一个缓冲区接收pickled的对象,它的值被填入第二个缓冲区,load()读取这个缓冲区。简单的数据库格式也可以使用pickle来存储对象。shelve模块就是这样一个实现。
除了存储数据,pickle对于进程间通信也很方便。例如,os.fork()和os.pipe()可以用来建立工作进程,从一个管道读取作业指令,并把结果写至另一个管道。管理工作线程池以及发送作业和接收响应的核心代码可以重用,因为作业和响应对象不必基于一个特定的类。使用管道或套接字时,在转储各个对象之后不要忘记刷新输出,以便将数据通过连接推送到另一端。参见multiprocessing模块来了解一个可重用的工作线程池管理器。
1.3 重构对象的问题
处理定制类时,pickled的类必须出现在读取pickle的进程所在的命名空间里。只会pickled这个实例的数据,而不是类定义。类名用于查找构造函数,以便在解除pickled时参见新对象。下面这个例子将一个类的实例写至一个文件。
- import pickleclass SimpleObject:
- def __init__(self, name):
- self.name = name
- l = list(name)
- l.reverse()
- self.name_backwards = ''.join(l)
- if __name__ == '__main__':