序列化 pickle模块
1. pickle 简介
2. pickle 核心函数
3. pickle 高级 —— 复杂对象
1. 持久化与 pickle 简介
1.1 什么是持久化?
持久化的基本思想很简单。假定有一个 Python 程序,它可能是一个管理日常待办事项的程序,你希望在多次执行这个程序之间可以保存应用程序对象(待办事项)。换句话说,你希望将对象存储在磁盘上,便于以后检索,这就是持久化。要达到这个目的,有几种方法,每一种方法都有其优缺点。
例如,可以将对象数据存储在某种格式的文本文件中,譬如 CSV 文件。或者可以用关系数据库,譬如 Gadfly、MySQL、PostgreSQL 或者 DB2。这些文件格式和数据库都非常优秀,对于所有这些存储机制,Python 都有健壮的接口。
这些存储机制都有一个共同点:存储的数据是独立于对这些数据进行操作的对象和程序。这样做的好处是,数据可以作为共享的资源,供其它应用程序使用。缺点是,用这种方式,可以允许其它程序访问对象的数据,这违背了面向对象的封装性原则 — 即对象的数据只能通过这个对象自身的公共(public)接口来访问。
另外,对于某些应用程序,关系数据库方法可能不是很理想。尤其是,关系数据库不理解对象。相反,关系数据库会强行使用自己的类型系统和关系数据模型(表),每张表包含一组元组(行),每行包含具有固定数目的静态类型字段(列)。如果应用程序的对象模型不能够方便地转换到关系模型,那么在将对象映射到元组以及将元组映射回对象方面,会碰到一定难度。这种困难常被称为阻碍性不匹配(impedence-mismatch)问题。
1.2 对象持久性
如果希望透明地存储 Python 对象,而不丢失其身份和类型等信息,则需要某种形式的对象序列化:它是一个将任意复杂的对象转成对象的文本或二进制表示的过程。同样,必须能够将对象经过序列化后的形式恢复到原有的对象。在 Python 中,这种序列化过程称为 pickle,可以将对象 pickle 成字符串、磁盘上的文件或者任何类似于文件的对象,也可以将这些字符串、文件或任何类似于文件的对象 unpickle 成原来的对象。
假定您喜欢将任何事物都保存成对象,而且希望避免将对象转换成某种基于非对象存储的开销;那么 pickle 文件可以提供这些好处,但有时可能需要比这种简单的 pickle 文件更健壮以及更具有可伸缩性的事物。例如,只用 pickle 不能解决命名和查找 pickle 文件这样的问题,另外,它也不能支持并发地访问持久性对象。如果需要这些方面的功能,则要求助类似于 ZODB(针对 Python 的 Z 对象数据库)这类数据库。ZODB 是一个健壮的、多用户的和面向对象的数据库系统,它能够存储和管理任意复杂的 Python 对象,并支持事务操作和并发控制。令人足够感兴趣的是,甚至 ZODB 也依靠 Python 的本机序列化能力。而要想有效地使用 ZODB,首先必须充分了解 pickle。
1.3 pickle 模块简介
pickle 提供了一个简单的持久化功能。可以将对象以文件的形式存放在磁盘上。
Python 中几乎所有的数据类型(列表、字典、集合、类等)都可以用 pickle 来序列化。pickle 序列化后的数据,可读性差,人一般无法识别。
pickle 的可移植性
从空间和时间上说,Pickle 是可移植的。例如,可以在 Linux 下创建一个 pickle,然后将它发送到在 Windows 或 Mac OS 下运行的 Python 程序。并且,当升级到更新版本的 Python 时,不必担心可能要废弃已有的 pickle。Python 开发人员已经保证 pickle 格式将可以向后兼容 Python 各个版本。事实上,在 pickle 模块中提供了有关目前以及所支持的格式方面的详细信息。
2. pickle 函数
pickle 模块提供了以下函数:
- dumps(object):将 python 对象转换(序列化)为字节(二进制)对象。
- loads(string):将二进制对象转换(反序列为)为 python 对象。
- dump(object, file):将对象写到文件,这个文件可以是实际的物理文件,也可以是任何类似于文件的对象,这个对象具有 write() 方法,可以接受单个的字符串参数。
- load(file):返回包含在 pickle 文件中的对象。
缺省情况下, dumps() 和 dump() 使用可打印的 ASCII 表示来创建 pickle。两者都有一个 final 参数(可选,如果为 True,则该参数指定用更快以及更小的二进制表示来创建 pickle)。loads() 和 load() 函数则会自动检测 pickle 是二进制格式还是文本格式。事实上,在 pickle 模块中记录了所有使用的约定。
2.1 dumps() 和 loads()
- dumps(object):将 python 对象转换(序列化)为字节(二进制)对象。
- loads(string):将二进制对象转换(反序列为)为 python 对象。
示例:
# 将对象序列化为二进制
>>> o1 = ("this is string", 42, [1,2,3], {1:2}, None)
>>> p1 = pickle.dumps(o1)
>>> print(p1)
b'\x80\x03(X\x0e\x00\x00\x00this is stringq\x00K*]q\x01(K\x01K\x02K\x03e}q\x02K\
x01K\x02sNtq\x03.' # 将二进制反序列化为对象
>>> o2 = pickle.loads(p1)
>>> print(o2)
('this is string', 42, [1, 2, 3], {1: 2}, None)
在以上示例中,使用的都是简单对象,因此使用二进制 pickle 格式不会在节省空间上显示出太大的效率。然而,在实际使用复杂对象的系统中,使用二进制格式可以在大小和速度方面带来显著的改进。
2.2 dump() 和 load()
- dump(object, file):将 python 对象写(序列化)到文件,这个文件可以是实际的物理文件,也可以是任何类似于文件的对象,这个对象具有 write() 方法,可以接受单个的字符串参数。
- load(file):从文件中将二进制对象读取(反序列化)为 python 对象。
dump() 和 load() ,它们使用文件和类似文件的对象。这些函数的操作非常类似于我们刚才所看到的 dumps() 和 loads() ,区别在于它们还有另一种能力 — dump() 函数能一个接着一个地将几个对象转储到同一个文件。随后调用 load() 来以同样的顺序检索这些对象。
示例:
1 # 将对象序列化到二进制文件中
2 >>> a1 = "apple"
3 >>> b1 = {1:"one", 2:"two"}
4 >>> c1 = [1,"two"]
5 >>> f1 = open("tmp.pkl", "wb")
6 >>> pickle.dump(a1, f1)
7 >>> pickle.dump(b1, f1)
8 >>> pickle.dump(c1, f1)
9 >>> f1.close()
10
11 # 按序(先入先出)从二进制文件中反序列为对象
12 >>> f2 = open("tmp.pkl", "rb")
13 >>> a2 = pickle.load(f2)
14 >>> a2
15 'apple'
16 >>> b2 = pickle.load(f2)
17 >>> b2
18 {1: 'one', 2: 'two'}
19 >>> c2 = pickle.load(f2)
20 >>> c2
21 [1, 'two']
22 >>> f2.close()
3. pickle 高级 —— 复杂对象
到目前为止,我们讲述了关于 pickle 方面的基本知识。在这一节,将讨论一些高级问题,当你开始 pickle 复杂对象时,会遇到这些问题,其中包括定制类的实例。幸运的是,Python 可以很容易地处理这种情形。
3.1 多个引用,同一对象
在 Python 中,变量是对象的引用。同时,也可以用多个变量引用同一个对象。经证明,Python 在用经过 pickle 的对象维护这种行为方面丝毫没有困难。
示例:对象引用的维护
1 >>> a = [1,2,3]
2 >>> b = a
3 >>> a
4 [1, 2, 3]
5 >>> b
6 [1, 2, 3]
7 >>>
8 >>> c = pickle.dumps((a,b))
9 >>> d, e = pickle.loads(c)
10 >>> d
11 [1, 2, 3]
12 >>> e
13 [1, 2, 3]
14 >>> d.append(4)
15 >>> e
16 [1, 2, 3, 4]
3.2 循环引用和递归引用
可以将刚才演示过的对象引用支持扩展到 递归引用(一个对象包含对其自身的引用)和 循环引用(两个对象各自包含对对方的引用)。
示例:递归引用
1 >>> li = [1,2,3]
2 >>> li.append(li)
3 >>> li
4 [1, 2, 3, [...]]
5 >>> li[3]
6 [1, 2, 3, [...]]
7 >>> li[3][3]
8 [1, 2, 3, [...]]
9 >>> p = pickle.dumps(li)
10 >>> li2 = pickle.loads(p)
11 >>> li2
12 [1, 2, 3, [...]]
13 >>> li2[3]
14 [1, 2, 3, [...]]
15 >>> li2[3][3]
16 [1, 2, 3, [...]]
示例:循环引用
1 >>> a = [1,2]
2 >>> b = [3,4]
3 >>> a.append(b)
4 >>> b.append(a)
5 >>> a
6 [1, 2, [3, 4, [...]]]
7 >>> b
8 [3, 4, [1, 2, [...]]]
9 >>> a[2]
10 [3, 4, [1, 2, [...]]]
11 >>> a[2] is b
12 True
13 >>> f1 = open("tmp.pkl","wb")
14 >>> pickle.dump((a,b), f1)
15 >>> f1.close()
16 >>>
17 >>> f2 = open("tmp.pkl", "rb")
18 >>> c,d = pickle.load(f2)
19 >>> f2.close()
20 >>> c
21 [1, 2, [3, 4, [...]]]
22 >>> d
23 [3, 4, [1, 2, [...]]]
24 >>> c[2] is d
25 True
3.3 分别 pickle vs. 在一个元组中一起 pickle
如果分别 pickle 每个对象,而不是在一个元组中一起 pickle 所有对象,会得到略微不同(但很重要)的结果:在 pickle 情形中,每个对象被恢复到一个与原来对象相等的对象,但不是同一个对象。换句话说,每个 pickle 都是原来对象的一个副本。
1 # 通过元组一起pickle
2 >>> a = [1,2]
3 >>> b = a
4 >>> f1 = open("tmp.pkl", "wb")
5 >>> pickle.dump((a,b), f1)
6 >>> f1.close()
7 >>>
8 >>> f2 = open("tmp.pkl", "rb")
9 >>> c,d = pickle.load(f2)
10 >>> c is a
11 False
12 >>> c is d
13 True
14 >>>
15
16 # 分别pickle
17 >>> f3 = open("tmp.pkl", "wb")
18 >>> f3.close()
19 >>> a2 = [1,2]
20 >>> b2 = a2
21 >>> f3 = open("tmp.pkl", "wb")
22 >>> pickle.dump(a2, f3)
23 >>> pickle.dump(b2, f3)
24 >>> f3.close()
25 >>>
26 >>> f4 = open("tmp.pkl", "rb")
27 >>> c2 = pickle.load(f4)
28 >>> d2 = pickle.load(f4)
29 >>> f4.close()
30 >>>
31 >>> c2
32 [1, 2]
33 >>> d2
34 [1, 2]
35 >>> c2 is d2
36 False
3.4 维护分别 pickle 的对象间的引用
有一个选项确实允许分别 pickle 对象,并维护相互之间的引用,只要这些对象都是 pickle 到同一文件即可。 pickle 模块提供了一个 Pickler (与此相对应是 Unpickler ),它能够跟踪已经被 pickle 的对象。通过使用这个 Pickler ,将会通过引用而不是通过值来 pickle 共享和循环引用。
1 >>> f1 = open("tmp.pkl", "wb")
2 >>> pickler = pickle.Pickler(f1)
3 >>> a = [1,2]
4 >>> b = a
5 >>> pickler.dump(a)
6 >>> pickler.dump(b)
7 >>> f1.close()
8 >>>
9 >>> f2 = open("tmp.pkl", "rb")
10 >>> unpickler = pickle.Unpickler(f2)
11 >>> c = unpickler.load()
12 >>> d = unpickler.load()
13 >>> c
14 [1, 2]
15 >>> d
16 [1, 2]
17 >>> c is d # 注意与上一个示例的结果不同
18 True
3.5 不可 pickle 的对象
一些对象类型是不可 pickle 的。例如,Python 不能 pickle 文件对象(或者任何带有对文件对象引用的对象),因为 Python 在 unpickle 时不能保证它可以重建该文件的状态。试图 pickle 文件对象会导致以下错误:
1 >>> f = open("tmp.pkl", "wb")
2 >>> pickle.dumps(f)
3 Traceback (most recent call last):
4 File "<stdin>", line 1, in <module>
5 TypeError: cannot serialize '_io.BufferedWriter' object
3.6 类实例
与 pickle 简单对象类型相比,pickle 类实例要多加留意。这主要由于 Python 会 pickle 实例数据(通常是 _dict_ 属性)和类的名称,而不会 pickle 类的代码。当 Python unpickle 类的实例时,它会试图使用在 pickle 该实例时的确切的类名称和模块名称(包括任何包的路径前缀)导入包含该类定义的模块。另外要注意,类定义必须出现在模块的最顶层,这意味着它们不能是嵌套的类(在其它类或函数中定义的类)。
当 unpickle 类的实例时,通常不会再调用它们的 _init_() 方法。相反,Python 创建一个通用类实例,并应用已进行过 pickle 的实例属性,同时设置该实例的 _class_ 属性,使其指向原来的类。
对 Python 2.2 中引入的新型类进行 unpickle 的机制与原来的略有不同。虽然处理的结果实际上与对旧型类处理的结果相同,但 Python 使用 copy_reg 模块的 _reconstructor() 函数来恢复新型类的实例。
如果希望对新型或旧型类的实例修改缺省的 pickle 行为,则可以定义特殊的类的方法 _getstate_() 和 _setstate_() ,在保存和恢复类实例的状态信息期间,Python 会调用这些方法。
序列化 pickle模块的更多相关文章
- Python第十四天 序列化 pickle模块 cPickle模块 JSON模块 API的两种格式
Python第十四天 序列化 pickle模块 cPickle模块 JSON模块 API的两种格式 目录 Pycharm使用技巧(转载) Python第一天 安装 shell 文件 Py ...
- 序列化pickle模块
1.pickle模块 pickle.dumps() 和pickle.loads() import pickle f = open('112.pkl','w') a = {'name':2,2:3,3: ...
- Python--模块之sys模块、logging模块、序列化json模块、序列化pickle模块
sys模块 sys.argv 命令行参数List,第一个元素是程序本身路径 sys.exit(n) 退出程序,正常退出时exit() sys.path 返回模块的搜索路径,初始化时使用PYTHONPA ...
- os模块、sys模块、json模块、pickle模块、logging模块
目录 os模块 sys模块 json模块 pickle模块 logging模块 os模块 功能:与操作系统交互,可以操作文件 一.对文件操作 判断是否为文件 os.path.isfile(r'路径') ...
- 各类模块的粗略总结(time,re,os,sys,序列化,pickle,shelve.#!json )
***collections 扩展数据类型*** ***re 正则相关操作 正则 匹配字符串*** ***time 时间相关 三种格式:时间戳,格式化时间(字符串),时间元组(结构化时间).***`` ...
- Pythoy 数据类型序列化——json&pickle 模块
Pythoy 数据类型序列化--json&pickle 模块 TOC 什么是序列化/反序列化 pickle 模块 json 模块 对比json和pickle json.tool 命令行接口 什 ...
- [python](windows)分布式进程问题:pickle模块不能序列化lambda函数
运行错误:_pickle.PicklingError: Can't pickle <function <lambda> at 0x000002BAAEF12F28>: attr ...
- 序列化模块— json模块,pickle模块,shelve模块
json模块 pickle模块 shelve模块 序列化——将原本的字典.列表等内容转换成一个字符串的过程就叫做序列化. # 序列化模块 # 数据类型转化成字符串的过程就是序列化 # 为了方便存储和网 ...
- python 常用模块(一): os模块,序列化模块(json模块 pickle模块 )
1.os模块 2.序列化模块:(1)json模块 和 pickle模块 一.os模块 os.path.abspath: (1)把路径中不符合规范的/改成操作系统默认的格式 import os path ...
随机推荐
- 微信小程序:优化页面要渲染的属性
问题:页面中只用到四个属性:goods_name,goods_price,goods_introduce,pics,但是整个对象中有22个属性,小程序中建议:data中只存放标签中要使用的数据,而现在 ...
- linux之安装nginx
nginx官网:http://nginx.org/en/download.html 1.安装nginx所需环境 a) PCRE pcre-devel 安装 # yum install -y pcre ...
- CentOS6.4 Install oh-my-zsh
先安装zsh yum -y install zsh # 查看是否安装完成 cat /etc/shells /bin/sh /bin/bash /sbin/nologin /bin/dash /bin/ ...
- matplotlib工具栏源码探析三(添加、删除自定义工具项)
转: matplotlib工具栏源码探析三(添加.删除自定义工具项) matplotlib工具栏源码探析二(添加.删除内置工具项)探讨了工具栏内置工具项的管理,除了内置工具项,很多场景中需要自定义工具 ...
- 内核报错kernel:NMI watchdog: BUG: soft lockup - CPU#1
1.现象描述 系统管理员电话通知,描述为一台服务器突然无法ssh连接,登录服务器带外IP地址并进入远程控制台界面后,提示Authentication error,重启后即可正常进入系统,进入后过20分 ...
- CodeBlocks的安装配置以及使用教程
CodeBlocks的安装配置以及使用教程 教程写的很啰嗦,本来几句话就能搞定的,但为了照顾到那部分真正的小白还请大家见谅! 一.下载 前往CodeBlocks官网下载带编译器的版本,目前的最新版本为 ...
- 基于dlib+django+python 实现web端人脸打卡
face_recognition 基于python+django+dlib实现的人脸打卡系统 开始之前 windows用户需要安装 VS2017 其他VS版本也行 linux用户需要安装c++编译器( ...
- CVE-2014-4210 SSRF漏洞
Weblogic中存在一个SSRF漏洞,利用该漏洞可以发送任意HTTP请求,进而攻击内网中redis.fastcgi等脆弱组件. 修复方式: 1.删除server/lib/uddiexplorer.w ...
- axios之增删查改操作
一.get方法获取数据 axios.get('url') .then(function (res) { console.log(res); }).catch(function (error) { co ...
- Solon 框架详解(九)- 渲染控制之定制统一的接口输出
Springboot min -Solon 详解系列文章: Springboot mini - Solon详解(一)- 快速入门 Springboot mini - Solon详解(二)- Solon ...