老生常谈Python序列化和反序列化


Posted in Python onJune 28, 2017

通过将对象序列化可以将其存储在变量或者文件中,可以保存当时对象的状态,实现其生命周期的延长。并且需要时可以再次将这个对象读取出来。Python中有几个常用模块可实现这一功能。

pickle模块

存储在变量中

dumps(obj)返回存入的字节

dic = {'age': 23, 'job': 'student'}
byte_data = pickle.dumps(dic)
# out -> b'\x80\x03}q\x00(X\x03\x00\x00\...'
print(byte_data)

读取数据

数据以字节保存在了byte_data变量中,需要再次使用的时候使用loads函数就行了。

obj = pickle.loads(byte_data)
print(obj)

存储在文件中

也可以存在文件中,使得对象持久化。使用的是dump和load函数,注意和上面的区别,少了s。由于pickle写入的是二进制数据,所以打开方式需要以wb和rb的模式。

# 序列化
with open('abc.pkl', 'wb') as f:
  dic = {'age': 23, 'job': 'student'}
  pickle.dump(dic, f)
# 反序列化
with open('abc.pkl', 'rb') as f:
  aa = pickle.load(f)
  print(aa)
  print(type(aa)) # <class 'dict'>

序列化用户自定义对象

假如我写了个类叫做Person

class Person:
  def __init__(self, name, age, job):
    self.name = name
    self.age = age
    self.job = job

  def work(self):
    print(self.name, 'is working...')

pickle当然也能写入,不仅可以写入类本身,也能写入它的一个实例。

# 将实例存储在变量中,当然也能存在文件中
a_person = Person('abc', 22, 'waiter')
person_abc = pickle.dumps(a_person)
p = pickle.loads(person_abc)
p.work()
# 将类本身存储在变量中,loads的时候返回类本身,而非它的一个实例
class_Person = pickle.dumps(Person)
Person = pickle.loads(class_Person)
p = Person('Bob', 23, 'Student')
p.work()

# 下面这个例子演示的就是将类存储在文件中
# 序列化
with open('person.pkl', 'wb') as f:
  pickle.dump(Person, f)
# 反序列化
with open('person.pkl', 'rb') as f:
  Person = pickle.load(f)
  aa = Person('gg', 23, '6')
  aa.work()

json模块

pickle可以很方便地序列化所有对象。不过json作为更为标准的格式,具有更好的可读性(pickle是二进制数据)和跨平台性。是个不错的选择。

json使用的四个函数名和pickle一致。

序列化为字符串

dic = {'age': 23, 'job': 'student'}
dic_str = json.dumps(dic)
print(type(dic_str), dic_str)
# out: <class 'str'> {"age": 23, "job": "student"}

dic_obj = json.loads(dic_str)
print(type(dic_obj), dic_obj)
# out: <class 'dict'> {'age': 23, 'job': 'student'}

可以看到,dumps函数将对象转换成了字符串。loads函数又将其恢复成字典。

存储为json文件

也可以存储在json文件中

dic = {'age': 23, 'job': 'student'}
with open('abc.json', 'w', encoding='utf-8') as f:
  json.dump(dic, f)

with open('abc.json', encoding='utf-8') as f:
  obj = json.load(f)
  print(obj)

存储自定义对象

还是上面的Person对象。如果直接序列化会报错

aa = Person('Bob', 23, 'Student')
with open('abc.json', 'w', encoding='utf-8') as f:
  json.dump(aa, f) # 报错

Object of type 'Person' is not JSON serializable此时dump函数里传一个参default就可以了,这个参数接受一个函数,这个函数可以将对象转换为字典。

写一个就是了

def person2dict(person):
  return {'name': person.name,
      'age': person.age,
      'job': person.job}

这样返回的就是一个字典了,对象实例有个方法可以简化这一过程。直接调用实例的__dict__。例如

print(aa.__dict) # {'name': 'Bob', 'age': 23, 'job': 'Student'}

很方便。

同时在读取的时候load出来的是一个字典,再转回对象就可,同样需要一个object_hook参数,该参数接收一个函数,用于将字典转为对象。

def dict2person(dic):
  return Person(dic['name'], dic['age'], dic['job'])

于是完整的程序应该写成下面这样

with open('abc.json', 'w', encoding='utf-8') as f:
  json.dump(aa, f, default=person2dict)

with open('abc.json', encoding='utf-8') as f:
  obj = json.load(f, object_hook=dict2person)
  print(obj.name, obj.age, obj.job)
  obj.work()

由于可以使用__dict__代替person2dict函数,再使用lambda函数简化。

with open('abc.json', 'w', encoding='utf-8') as f:
  json.dump(aa, f, default=lambda obj: obj.__dict__)

以上是存储到文件,存储到变量也是类似操作。

不过就我现在所学,不知道如何像pickle一样方便的将我们自定义的类本身使用json序列化,或许要用到其他扩展函数。以后用到了再说。

shelve模块

还有一个模块,不太常用,通常使用一个open就好。shelve以键值对的形式存储数据。

with shelve.open('aa') as f:
  f['person'] = {'age': 23, 'job': 'student'}
  f['person']['age'] = 44 # 这里试图改变原来的年龄23
  f['numbers'] = [i for i in range(10)]

with shelve.open('aa') as f:
  person = f['person']
  print(person) # {'age': 23, 'job': 'student'}
  nums = f['numbers']
  print(nums) # [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

文件不要有后缀名,在windows下会生成aa.bak, aa.dat, aa.dir三个文件(有点多)。其中bak和dir文件是可以查看的(貌似两个文件内容一样)在下面这个例子中生成这样的数据。

'person', (0, 44)
'numbers', (512, 28)

允许写回--writeback

有个细节,我们读取键person时候,发现age还是23岁,f['person']['age'] = 44后并没有变成44。下面的写法

with shelve.open('aa', writeback=True) as f:
  dic = {'age': 23, 'job': 'student'}
  f['person'] = dic
  dic['age'] = 44
  f['person'] = dic

相当于赋值了两次,这种方法是可以改变值的。

默认情况下直接使用f['person']改变其中的值之后,不会更新已存储的值,也就是没有把更新写回到文件,即使是文件被close后。如果有此需要,在open函数中添加一个参数writeback=True。再次运行下看看年龄就被改变了。

写入自定义对象

依然使用上面的Person对象

with shelve.open('aa') as f:
  f['class'] = Person
  
# 写入类本身
with shelve.open('aa') as f:
  Person = f['class']
  a = Person('Bob', 23, 'Student')
  a.work()

上面的例子说明shelve也可以序列化类本身。当然序列化实例肯定可以。

with shelve.open('aa') as f:
  a = Person('God', 100, 'watch')
  f['class'] = a

with shelve.open('aa') as f:
  god = f['class']
  god.work()

注意,由于我们使用with open打开,故不用写close语句,此模块是有close函数的,如果不是with方法打开的一定要记得主动close。

以上这篇老生常谈Python序列化和反序列化就是小编分享给大家的全部内容了,希望能给大家一个参考,也希望大家多多支持三水点靠木。

Python 相关文章推荐
简单介绍Python的轻便web框架Bottle
Apr 08 Python
使用Python编写一个在Linux下实现截图分享的脚本的教程
Apr 24 Python
Python中扩展包的安装方法详解
Jun 14 Python
pygame 精灵的行走及二段跳的实现方法(必看篇)
Jul 10 Python
Python3中的列表,元组,字典,字符串相关知识小结
Nov 10 Python
Python搭建FTP服务器的方法示例
Jan 19 Python
python监控文件并且发送告警邮件
Jun 21 Python
Python 监测文件是否更新的方法
Jun 10 Python
Python正则表达式匹配日期与时间的方法
Jul 07 Python
使用PyCharm官方中文语言包汉化PyCharm
Nov 18 Python
Django多个app urls配置代码实例
Nov 26 Python
python 爬取京东指定商品评论并进行情感分析
May 27 Python
python flask实现分页效果
Jun 27 #Python
Django自定义分页效果
Jun 27 #Python
Python读取和处理文件后缀为.sqlite的数据文件(实例讲解)
Jun 27 #Python
最近Python有点火? 给你7个学习它的理由!
Jun 26 #Python
Python的装饰器使用详解
Jun 26 #Python
Python学习思维导图(必看篇)
Jun 26 #Python
python flask 多对多表查询功能
Jun 25 #Python
You might like
php使用Jpgraph绘制柱形图的方法
2015/06/10 PHP
PHP MYSQL简易交互式站点开发
2016/12/27 PHP
PHP实现根据密码长度显示安全条
2017/07/04 PHP
Javascript实现的分页函数
2006/12/22 Javascript
js鼠标滑过弹出层的定位IE6bug解决办法
2012/12/26 Javascript
jquery选择器大全 全面详解jquery选择器
2014/03/06 Javascript
javascript中$(function() {});写与不写有哪些区别
2015/08/10 Javascript
JSON 的正确用法探讨:Pyhong、MongoDB、JavaScript与Ajax
2016/05/15 Javascript
解决npm管理员身份install时出现权限的问题
2018/03/16 Javascript
JS实现的视频弹幕效果示例
2018/08/17 Javascript
Vue父子组件之间的通信实例详解
2018/09/28 Javascript
如何解决vue在ios微信&quot;复制链接&quot;功能问题
2020/03/26 Javascript
[01:01:42]Secret vs Optic Supermajor 胜者组 BO3 第二场 6.4
2018/06/05 DOTA
[01:06]DOTA2小知识课堂 Ep.02 吹风竟可解梦境缠绕
2019/12/05 DOTA
举例简单讲解Python中的数据存储模块shelve的用法
2016/03/03 Python
Python 获得13位unix时间戳的方法
2017/10/20 Python
django框架之cookie/session的使用示例(小结)
2018/10/15 Python
python中强大的format函数实例详解
2018/12/05 Python
Python 3.x基于Xml数据的Http请求方法
2018/12/28 Python
jupyter notebook参数化运行python方式
2020/04/10 Python
完美解决Django2.0中models下的ForeignKey()问题
2020/05/19 Python
Python模拟登入的N种方式(建议收藏)
2020/05/31 Python
CSS3基础(RGBa、text-shadow、box-shadow、border-radius)
2012/11/13 HTML / CSS
CSS3之边框多颜色Border-color属性使用示例
2013/10/11 HTML / CSS
世界第一冲浪品牌:O’Neill
2016/08/30 全球购物
AHAVA美国官方网站:死海海泥护肤品牌
2016/10/18 全球购物
.net面试题
2015/12/22 面试题
请写出一段Python代码实现删除一个list里面的重复元素
2015/12/29 面试题
MVC的各个部分都有那些技术来实现?如何实现?
2016/04/21 面试题
如何写自我评价?自我评价写什么好?
2014/03/14 职场文书
媒体宣传策划方案
2014/05/25 职场文书
售后客服工作职责
2014/06/16 职场文书
储备店长岗位职责
2015/04/14 职场文书
原告离婚代理词
2015/05/23 职场文书
商务信函英语问候语
2015/11/10 职场文书
煤矿施工安全协议书
2016/03/22 职场文书