详解Python中的序列化与反序列化的使用


Posted in Python onJune 30, 2015

学习过marshal模块用于序列化和反序列化,但marshal的功能比较薄弱,只支持部分内置数据类型的序列化/反序列化,对于用户自定义的类型就无能为力,同时marshal不支持自引用(递归引用)的对象的序列化。所以直接使用marshal来序列化/反序列化可能不是很方便。还好,python标准库提供了功能更加强大且更加安全的pickle和cPickle模块。

cPickle模块是使用C语言实现的,所以在运行效率上比pickle要高。但是cPickle模块中定义的类型不能被继承(其实大多数时候,我们不需要从这些类型中继承。)。cPickle和pickle的序列化/反序列化规则是一样的,我们可以使用pickle序列化一个对象,然后使用cPickle来反序列化。同时,这两个模块在处理自引用类型时会变得更加“聪明”,它不会无限制的递归序列化自引用对象,对于同一对象的多次引用,它只会序列化一次。例如:
 

import marshal, pickle
 
list = [1]
list.append(list)
byt1 = marshal.dumps(list) 
#出错, 无限制的递归序列化
byt2 = pickle.dumps(list) 
#No problem
pickle的序列化规则

Python规范(Python-specific)提供了pickle的序列化规则。这就不必担心不同版本的Python之间序列化兼容性问题。默认情况下,pickle的序列化是基于文本的,我们可以直接用文本编辑器查看序列化的文本。我们也可以序列成二进制格式的数据,这样的结果体积会更小。更详细的内容,可以参考Python手册pickle模块。

下面就开始使用pickle吧~
pickle.dump(obj, file[, protocol])

序列化对象,并将结果数据流写入到文件对象中。参数protocol是序列化模式,默认值为0,表示以文本的形式序列化。protocol的值还可以是1或2,表示以二进制的形式序列化。
pickle.load(file)

反序列化对象。将文件中的数据解析为一个Python对象。下面通过一个简单的例子来演示上面两个方法的使用:
 

#coding=gbk
 
import pickle, StringIO
 
class Person(object):
 
'''自定义类型。
 
'''
 def __init__(self, name, address):
  self.name = name
  self.address = address
  
  def display(self):
  print 'name:', self.name, 'address:', self.address 
 
jj = Person("JGood", "中国 杭州")
jj.display()
file = StringIO.StringIO()
 
pickle.dump(jj, file, 0) 
#序列化
#print file.getvalue() #打印序列化后的结果
  
#del Person #反序列的时候,必须能找到对应类的定义。否则反序列化操作失败。
file.seek(0)
jj1 = pickle.load(file) 
#反序列化
jj1.display()
file.close()

注意:在反序列化的时候,必须能找到对应类的定义,否则反序列化将失败。在上面的例子中,如果取消#del Person的注释,在运行时将抛AttributeError异常,提示当前模块找不到Person的定义。
pickle.dumps(obj[, protocol])
pickle.loads(string)

我们也可以直接获取序列化后的数据流,或者直接从数据流反序列化。方法dumps与loads就完成这样的功能。dumps返回序列化后的数据流,loads返回的序列化生成的对象。

python模块中还定义了两个类,分别用来序列化、反序列化对象。
class pickle.Pickler(file[, protocal]):

该类用于序列化对象。参数file是一个类文件对象(file-like object),用于保存序列化结果。可选参数表示序列化模式。它定义了两个方法:
dump(obj):

将对象序列化,并保存到类文件对象中。参数obj是要序列化的对象。
clear_memo()

清空pickler的“备忘”。使用Pickler实例在序列化对象的时候,它会“记住”已经被序列化的对象引用,所以对同一对象多次调用dump(obj),pickler不会“傻傻”的去多次序列化。下面是一个简单的例子:
 

#coding=gbk
import pickle, StringIO
 
class Person(object):
 
'''自定义类型。
 
'''
 def __init__(self, name, address):
  self.name = name
  self.address = address
  
 def display(self):
  print 'name:', self.name, 'address:', self.address 
   
fle = StringIO.StringIO()
pick = pickle.Pickler(fle)
person = Person("JGood", "Hangzhou China") 
 
pick.dump(person)
val1 = fle.getvalue()
print len(val1)
 
pick.clear_memo() 
#注释此句,再看看运行结果
 
pick.dump(person) 
#对同一引用对象再次进行序列化
val2 = fle.getvalue()
print len(val2)
 
#---- 结果 ----
#148
#296
#
#将这行代码注释掉:pick.clear_memo()
#结果为:
#148
#152
class pickle.Unpickler(file):

该类用于反序列化对象。参数file是一个类文件(file-like object)对象,Unpickler从该参数中获取数据进行反序列化。
load():

反序列化对象。该方法会根据已经序列化的数据流,自动选择合适的反序列化模式。
 

#.... 接上个例子中的代码
 
fle.seek(0)
unpick = pickle.Unpickler(fle)
print unpick.load()

上面介绍了pickle模块的基本使用,但和marshal一样,并不是所有的类型都可以通过pickle序列化的。例如对于一个嵌套的类型,使用pickle序列化就失败。例如:
 

class A(object):
 class B(object):
  def __init__(self, name):
   self.name = name
  
 def __init__(self):
  print 'init A'
 
b = A.B("my name")
print b
c = pickle.dumps(b, 0) 
#失败哦
print pickle.loads(c)

关于pickle支持的序列化类型,可以参考Python手册。

Python 相关文章推荐
Python实现Linux命令xxd -i功能
Mar 06 Python
python实现逆序输出一个数字的示例讲解
Jun 25 Python
Python实现的从右到左字符串替换方法示例
Jul 06 Python
Flask和Django框架中自定义模型类的表名、父类相关问题分析
Jul 19 Python
python/sympy求解矩阵方程的方法
Nov 08 Python
简单了解python中对象的取反运算符
Jul 01 Python
python实现猜数字游戏
Mar 25 Python
pygame实现俄罗斯方块游戏(基础篇1)
Oct 29 Python
python入门之基础语法学习笔记
Feb 08 Python
Python实现曲线拟合的最小二乘法
Feb 19 Python
Python一些基本的图像操作和处理总结
Jun 23 Python
python使用torch随机初始化参数
Mar 22 Python
Python中函数的参数传递与可变长参数介绍
Jun 30 #Python
python实现文件快照加密保护的方法
Jun 30 #Python
Python实现高效求解素数代码实例
Jun 30 #Python
python实现DES加密解密方法实例详解
Jun 30 #Python
python实现的系统实用log类实例
Jun 30 #Python
python实现在windows服务中新建进程的方法
Jun 30 #Python
python实现线程池的方法
Jun 30 #Python
You might like
印尼林东PWN黄金曼特宁咖啡豆:怎么冲世界上最醇厚的咖啡冲煮教程
2021/03/03 冲泡冲煮
用XMLDOM和ADODB.Stream实现base64编码解码实现代码
2010/11/28 Javascript
jquery ajax 局部刷新小案例
2014/02/08 Javascript
js实现ctrl+v粘贴上传图片(兼容chrome、firefox、ie11)
2016/03/09 Javascript
JS获取和修改元素样式的实例代码
2016/08/06 Javascript
js中判断变量类型函数typeof的用法总结
2016/08/09 Javascript
前端实现文件的断点续传(前端文件提交+后端PHP文件接收)
2016/11/04 Javascript
JavaScript用构造函数如何获取变量的类型名
2016/12/23 Javascript
BootStrap实现轮播图效果(收藏)
2016/12/30 Javascript
jQuery简单实现MD5加密的方法
2017/03/03 Javascript
vue与bootstrap实现时间选择器的示例代码
2017/08/26 Javascript
关于 angularJS的一些用法
2017/11/29 Javascript
详解webpack之scss和postcss-loader的配置
2018/01/09 Javascript
解决vue中对象属性改变视图不更新的问题
2018/02/23 Javascript
node 使用 async 控制并发的方法
2018/05/07 Javascript
在vue使用clipboard.js进行一键复制文本的实现示例
2019/01/15 Javascript
JavaScript数据结构与算法之二叉树实现查找最小值、最大值、给定值算法示例
2019/03/01 Javascript
electron+vue实现div contenteditable截图功能
2020/01/07 Javascript
在Webpack中用url-loader处理图片和字体的问题
2020/04/28 Javascript
webpack+express实现文件精确缓存的示例代码
2020/06/11 Javascript
如何构建 vue-ssr 项目的方法步骤
2020/08/04 Javascript
Python列表list操作符实例分析【标准类型操作符、切片、连接字符、列表解析、重复操作等】
2017/07/24 Python
pytorch + visdom CNN处理自建图片数据集的方法
2018/06/04 Python
Python Opencv任意形状目标检测并绘制框图
2019/07/23 Python
python爬虫实现POST request payload形式的请求
2020/04/30 Python
Python实现Canny及Hough算法代码实例解析
2020/08/06 Python
法国在线宠物店:zooplus.fr
2018/02/23 全球购物
Java里面如何创建一个内部类的实例
2015/01/19 面试题
商场中秋节活动方案
2014/02/07 职场文书
公司任命书模板
2014/06/06 职场文书
标准大学生职业生涯规划书写作指南
2014/09/18 职场文书
统计工作个人总结
2015/03/03 职场文书
堂吉诃德读书笔记
2015/06/30 职场文书
pycharm无法导入lxml的解决办法
2021/03/31 Python
python 进阶学习之python装饰器小结
2021/09/04 Python
关于Vue中的options选项
2022/03/22 Vue.js