序列化Python对象的方法


Posted in Python onAugust 01, 2020

问题

你需要将一个Python对象序列化为一个字节流,以便将它保存到一个文件、存储到数据库或者通过网络传输它。

解决方案

对于序列化最普遍的做法就是使用 pickle 模块。为了将一个对象保存到一个文件中,可以这样做:

import pickle

data = ... # Some Python object
f = open('somefile', 'wb')
pickle.dump(data, f)

为了将一个对象转储为一个字符串,可以使用 pickle.dumps()

s = pickle.dumps(data)

为了从字节流中恢复一个对象,使用 pickle.load() pickle.loads() 函数。比如:

# Restore from a file
f = open('somefile', 'rb')
data = pickle.load(f)

# Restore from a string
data = pickle.loads(s)

讨论

对于大多数应用程序来讲,dump() load() 函数的使用就是你有效使用 pickle 模块所需的全部了。 它可适用于绝大部分Python数据类型和用户自定义类的对象实例。 如果你碰到某个库可以让你在数据库中保存/恢复Python对象或者是通过网络传输对象的话, 那么很有可能这个库的底层就使用了 pickle 模块。

pickle 是一种Python特有的自描述的数据编码。 通过自描述,被序列化后的数据包含每个对象开始和结束以及它的类型信息。 因此,你无需担心对象记录的定义,它总是能工作。 举个例子,如果要处理多个对象,你可以这样做:

>>> import pickle
>>> f = open('somedata', 'wb')
>>> pickle.dump([1, 2, 3, 4], f)
>>> pickle.dump('hello', f)
>>> pickle.dump({'Apple', 'Pear', 'Banana'}, f)
>>> f.close()
>>> f = open('somedata', 'rb')
>>> pickle.load(f)
[1, 2, 3, 4]
>>> pickle.load(f)
'hello'
>>> pickle.load(f)
{'Apple', 'Pear', 'Banana'}
>>>

你还能序列化函数,类,还有接口,但是结果数据仅仅将它们的名称编码成对应的代码对象。例如:

>>> import math
>>> import pickle.
>>> pickle.dumps(math.cos)
b'\x80\x03cmath\ncos\nq\x00.'
>>>

当数据反序列化回来的时候,会先假定所有的源数据时可用的。 模块、类和函数会自动按需导入进来。对于Python数据被不同机器上的解析器所共享的应用程序而言, 数据的保存可能会有问题,因为所有的机器都必须访问同一个源代码。

千万不要对不信任的数据使用pickle.load()。
pickle在加载时有一个副作用就是它会自动加载相应模块并构造实例对象。
但是某个坏人如果知道pickle的工作原理,
他就可以创建一个恶意的数据导致Python执行随意指定的系统命令。
因此,一定要保证pickle只在相互之间可以认证对方的解析器的内部使用。

有些类型的对象是不能被序列化的。这些通常是那些依赖外部系统状态的对象, 比如打开的文件,网络连接,线程,进程,栈帧等等。 用户自定义类可以通过提供 __getstate__() __setstate__() 方法来绕过这些限制。 如果定义了这两个方法,pickle.dump() 就会调用 __getstate__() 获取序列化的对象。 类似的,__setstate__() 在反序列化时被调用。为了演示这个工作原理, 下面是一个在内部定义了一个线程但仍然可以序列化和反序列化的类:

# countdown.py
import time
import threading

class Countdown:
  def __init__(self, n):
    self.n = n
    self.thr = threading.Thread(target=self.run)
    self.thr.daemon = True
    self.thr.start()

  def run(self):
    while self.n > 0:
      print('T-minus', self.n)
      self.n -= 1
      time.sleep(5)

  def __getstate__(self):
    return self.n

  def __setstate__(self, n):
    self.__init__(n)

试着运行下面的序列化试验代码:

>>> import countdown
>>> c = countdown.Countdown(30)
>>> T-minus 30
T-minus 29
T-minus 28
...

>>> # After a few moments
>>> f = open('cstate.p', 'wb')
>>> import pickle
>>> pickle.dump(c, f)
>>> f.close()

然后退出Python解析器并重启后再试验下:

>>> f = open('cstate.p', 'rb')
>>> pickle.load(f)
countdown.Countdown object at 0x10069e2d0>
T-minus 19
T-minus 18
...

你可以看到线程又奇迹般的重生了,从你第一次序列化它的地方又恢复过来。

pickle 对于大型的数据结构比如使用 arraynumpy 模块创建的二进制数组效率并不是一个高效的编码方式。 如果你需要移动大量的数组数据,你最好是先在一个文件中将其保存为数组数据块或使用更高级的标准编码方式如HDF5 (需要第三方库的支持)。

由于 pickle 是Python特有的并且附着在源码上,所有如果需要长期存储数据的时候不应该选用它。 例如,如果源码变动了,你所有的存储数据可能会被破坏并且变得不可读取。 坦白来讲,对于在数据库和存档文件中存储数据时,你最好使用更加标准的数据编码格式如XML,CSV或JSON。 这些编码格式更标准,可以被不同的语言支持,并且也能很好的适应源码变更。

最后一点要注意的是 pickle 有大量的配置选项和一些棘手的问题。 对于最常见的使用场景,你不需要去担心这个,但是如果你要在一个重要的程序中使用pickle去做序列化的话, 最好去查阅一下 官方文档 。

以上就是序列化Python对象的方法的详细内容,更多关于序列化Python对象的资料请关注三水点靠木其它相关文章!

Python 相关文章推荐
疯狂上涨的Python 开发者应从2.x还是3.x着手?
Nov 16 Python
对numpy 数组和矩阵的乘法的进一步理解
Apr 04 Python
Tensorflow 查看变量的值方法
Jun 14 Python
用python代码将tiff图片存储到jpg的方法
Dec 04 Python
在Python 中同一个类两个函数间变量的调用方法
Jan 31 Python
Python根据成绩分析系统浅析
Feb 11 Python
使用python itchat包爬取微信好友头像形成矩形头像集的方法
Feb 21 Python
Python神奇的内置函数locals的实例讲解
Feb 22 Python
python实现文件的分割与合并
Aug 29 Python
python内置模块collections知识点总结
Dec 19 Python
python 使用多线程创建一个Buffer缓存器的实现思路
Jul 02 Python
分布式全文检索引擎ElasticSearch原理及使用实例
Nov 14 Python
Python 忽略文件名编码的方法
Aug 01 #Python
Python 如何展开嵌套的序列
Aug 01 #Python
Python 日期与时间转换的方法
Aug 01 #Python
Python 执行矩阵与线性代数运算
Aug 01 #Python
Python实现数字的格式化输出
Aug 01 #Python
Python实现一个简单的递归下降分析器
Aug 01 #Python
Python 如何在字符串中插入变量
Aug 01 #Python
You might like
dedecms系统的广告设置代码 基础版本
2010/04/09 PHP
利用浏览器的Javascript控制台调试PHP程序
2014/01/08 PHP
php创建和删除目录函数介绍和递归删除目录函数分享
2014/11/18 PHP
深入理解PHP中的Streams工具
2015/07/03 PHP
解析dom中的children对象数组元素firstChild,lastChild的使用
2013/07/10 Javascript
引用外部脚本时script标签关闭的写法
2014/01/20 Javascript
AngularJS中的Directive自定义一个表格
2016/01/25 Javascript
纯js代码制作的网页时钟特效【附实例】
2016/03/30 Javascript
使用three.js 画渐变的直线
2016/06/05 Javascript
JS/jQ实现免费获取手机验证码倒计时效果
2016/06/13 Javascript
让编辑器支持word复制黏贴、截屏的js代码
2016/10/17 Javascript
使用Curl命令查看请求响应时间方法
2016/11/04 Javascript
Bootstrap面板学习使用
2017/02/09 Javascript
js实现同一个页面,多个enter事件绑定的示例
2018/10/10 Javascript
vue学习之Vue-Router用法实例分析
2020/01/06 Javascript
解决vux 中popup 组件Mask 遮罩在最上层的问题
2020/11/03 Javascript
[48:00]完美世界DOTA2联赛循环赛 Forest vs Inki BO2第二场 11.04
2020/11/04 DOTA
关于pip的安装,更新,卸载模块以及使用方法(详解)
2017/05/19 Python
Django实现快速分页的方法实例
2017/10/22 Python
python清理子进程机制剖析
2017/11/23 Python
为什么你还不懂得怎么使用Python协程
2019/05/13 Python
Python将视频或者动态图gif逐帧保存为图片的方法
2019/09/10 Python
基于python的selenium两种文件上传操作实现详解
2019/09/19 Python
pytorch torch.expand和torch.repeat的区别详解
2019/11/05 Python
Python正则表达式学习小例子
2020/03/03 Python
python编写一个会算账的脚本的示例代码
2020/06/02 Python
实例教程 HTML5 Canvas 超炫酷烟花绽放动画实现代码
2014/11/05 HTML / CSS
Nobody Denim官网:购买高级女士牛仔裤
2021/03/15 全球购物
教育学专业毕业生的自我评价
2013/11/21 职场文书
关于是否需要写商业计划书
2014/02/07 职场文书
公司年会主持词
2014/03/22 职场文书
松材线虫病防治方案
2014/06/15 职场文书
年度考核个人总结
2015/03/06 职场文书
2015年社区计生工作总结
2015/04/21 职场文书
2015年教师节主持词
2015/07/03 职场文书
Java基于字符界面的简易收银台
2021/06/26 Java/Android