1、什么是对象序列化
序列化(serialization)指的是将对象的状态信息转换为可以存储或传输的形式的过程。在序列化期间,对象将其当前状态写入到临时或持久性存储区。以后,可以通过从存储区中读取或反序列化对象的状态,重新创建该对象。
通常,对象实例的所有字段都会被序列化,这意味着数据会被表示为实例的序列化数据。这样,能够解释该格式的代码有可能能够确定这些数据的值,而不依赖于该成员的可访问性。类似地,反序列化从序列化的表示形式中提取数据,并直接设置对象状态,这也与可访问性规则无关。
2、序列化的目的
1、以某种存储形式使自定义对象持久化;
2、将对象从一个地方传递到另一个地方;
3、使程序更具维护性。
3、Python中的对象序列化
对于对象持久化而言,可以将对象数据存储在某种格式的文本文件中,譬如 CSV 文件。或者可以用关系数据库,譬如MySQL、PostgreSQL 或者 DB2。对于所有这些存储机制,Python 都有健壮的接口。这些存储机制存储的数据是独立于对这些数据进行操作的对象和程序的。这样做的好处是:数据可以作为共享的资源,供其它应用程序使用。缺点是:用这种方式,可以允许其它程序访问对象的数据。这违背了面向对象的封装性原则 — 即对象的数据只能通过这个对象自身的公共(public)接口来访问。另外,对于某些应用程序,关系数据库方法不是很理想。关系数据库并不理解对象,并且会强行使用自己的类型系统和关系数据模型(表),每张表包含一组元组(行),每行包含具有固定数目的静态类型字段(列)。如果应用程序的对象模型不能够方便地转换到关系模型,那么在将对象映射到元组以及将元组映射回对象方面,会碰到一定难度。这种困难常被称为阻碍性不匹配(impedance-mismatch)问题。
Object Model(对象模型)和RelationalModel(关系模型)不能匹配具体表现在以下几个方面:
在 Python 中,解决序列化问题需要利用 pickle,可以将对象 pickle 成字符串、磁盘上的文件或者任何类似于文件的对象,也可以将这些字符串、文件或任何类似于文件的对象 unpickle 成原来的对象。
基本用法:
pickle.dump(obj, file[, protocol])
这是将对象持久化的方法,参数的含义分别为:
obj: 要持久化保存的对象;
file: 一个拥有 write() 方法的对象,并且这个 write() 方法能接收一个字符串作为参数。这个对象可以是一个以写模式打开的文件对象或者一个 StringIO 对象,或者其他自定义的满足条件的对象。
protocol: 这是一个可选的参数,默认为 0 ,如果设置为 1 或 True,则以高压缩的二进制格式保存持久化后的对象,否则以ASCII格式保存。
pickle.load(file)
只有一个参数 file ,对应于上面 dump 方法中的 file 参数。这个 file 必须是一个拥有一个能接收一个整数为参数的 read() 方法以及一个不接收任何参数的 readline() 方法,并且这两个方法的返回值都应该是字符串。这可以是一个打开为读的文件对象、StringIO 对象或其他任何满足条件的对象。
可以被pickle 的东西:- 所有Python支持的 原生类型 : 布尔, 整数, 浮点数, 复数, 字符串,
bytes
(字节串)对象, 字节数组, 以及None
. - 由任何原生类型组成的列表,元组,字典和集合。
- 由任何原生类型组成的列表,元组,字典和集合组成的列表,元组,字典和集合(可以一直嵌套下去,直至Python支持的最大递归层数).
- 函数,类,和类的实例(带警告)。
pickle
模块也是可扩展的。cPickle 向 Python 也提供了 pickle 支持。
并且是用 C 编码的,具有更好的性能,对于大多数应用程序,推荐使用该模块
(Python3中,这两个模块已经合并,直接 import pickle
就可以)。4、pickle使用的一些问题
pickle是可移植的
pickle 是可移植的。pickle 文件格式独立于机器的体系结构,这意味着,可以在 Linux 下创建一个 pickle,然后将它发送到在 Windows 或 Mac OS 下运行的 Python 程序。并且,当升级到更新版本的 Python 时,不必担心可能要废弃已有的 pickle。Python 开发人员已经保证 pickle 格式将可以向后兼容 Python 各个版本。事实上,在 pickle 模块中提供了有关目前以及所支持的格式方面的详细信息:
检索所支持的格式:
>>> import pickle
>>> pickle.format_version
'2.0'
>>> pickle.compatible_formats
['1.0', '1.1', '1.2', '1.3', '2.0']
多个引用,同一对象
在 Python 中,变量是对象的引用,可以用多个变量引用同一个对象。Python 在用经过 pickle 的对象维护这种行为方面丝毫没有困难。
>>> a = [1, 2]
>>> b = a
>>> a.append(3)
>>> a
[1, 2, 3]
>>> b
[1, 2, 3]
>>> c = pickle.dumps((a, b))
>>>
>>> d, e = pickle.loads(c)
>>> d
[1, 2, 3]
>>> e
[1, 2, 3]
>>> d.append(4)
>>> d
[1, 2, 3, 4]
>>> e
[1, 2, 3, 4]
不可 pickle 的对象
一些对象类型是不可 pickle 的。例如,Python 不能 pickle 文件对象(或者任何带有对文件对象引用的对象),因为 Python 在 unpickle 时不能保证它可以重建该文件的状态。
>>> f = open('out.txt')
>>> p = pickle.dumps(f)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/usr/lib/python2.7/pickle.py", line 1374, in dumps
Pickler(file, protocol).dump(obj)
File "/usr/lib/python2.7/pickle.py", line 224, in dump
self.save(obj)
File "/usr/lib/python2.7/pickle.py", line 306, in save
rv = reduce(self.proto)
File "/usr/lib/python2.7/copy_reg.py", line 70, in _reduce_ex
raise TypeError, "can't pickle %s objects" % base.__name__
TypeError: can't pickle file objects
类实例
由于 Python 会 pickle 实例数据(通常是 _dict_ 属性)和类的名称,而不会 pickle 类的代码。当 Python unpickle 类的实例时,它会试图使用在 pickle 该实例时的确切的类名称和模块名称(包括任何包的路径前缀)导入包含该类定义的模块。类定义必须出现在模块的最顶层,它们不能是嵌套的类(在其它类或函数中定义的类)。
当 unpickle 类的实例时,通常不会再调用它们的 _init_() 方法。相反,Python 创建一个通用类实例,并应用已进行过 pickle 的实例属性,同时设置该实例的 _class_ 属性,使其指向原来的类。
5、参考
51CTO:LINUX应用技巧,序列化存储 Python 对象。http://developer.51cto.com/art/200509/3892.htm