当前位置: 首页 > 编程日记 > 正文

一文了解Python常见的序列化操作

关于我
编程界的一名小小程序猿,目前在一个创业团队任team lead,技术栈涉及Android、Python、Java和Go,这个也是我们团队的主要技术栈。 联系:hylinux1024@gmail.com

0x00 marshal

marshal使用的是与Python语言相关但与机器无关的二进制来读写Python对象的。这种二进制的格式也跟Python语言的版本相关,marshal序列化的格式对不同的版本的Python是不兼容的。

marshal一般用于Python内部对象的序列化。

一般地包括:

  • 基本类型 booleans, integers,floating point numbers,complex numbers
  • 序列集合类型 strings, bytes, bytearray, tuple, list, set, frozenset, dictionary
  • code对象 code object
  • 其它类型 None, Ellipsis, StopIteration

marshal的主要作用是对Python“编译”的.pyc文件读写的支持。这也是marshalPython版本不兼容的原因。开发者如果要使用序列化/反序列化,那么应该使用pickle模块。

常见的方法

marshal.dump(value, file[, version])
复制代码

序列化一个对象到文件中

marshal.dumps(value[, version])
复制代码

序列化一个对象并返回一个bytes对象

marshal.load(file)
复制代码

从文件中反序列化一个对象

marshal.loads(bytes)
复制代码

bytes二进制数据中反序列化一个对象

0x01 pickle

pickle模块也能够以二进制的方式对Python对象进行读写。相比marshal提供基本的序列化能力,pickle的序列化应用更加广泛。

pickle序列化后的数据也是与Python语言相关的,即其它语言例如Java无法读取由Python通过pickle序列化的二进制数据。如果要使用与语言无法的序列化那么我们应该使用json。下文将会说明。

能被pickle序列化的数据类型有:

  • None, True, and False
  • integers, floating point numbers, complex numbers
  • strings, bytes, bytearrays
  • tuples, lists, sets, and dictionaries 以及包含可以被pickle序列化对象
  • 在模块顶层定义的函数对象 (使用 def定义的, 而不是 lambda表达式)
  • 在模块顶层定义内置函数
  • 在模式顶层定义的类
  • 一个类的__dict__包含了可序列化的对象或__getstate__()方法返回了能够被序列化的对象

如果pickle一个不支持序列化的对象时将会抛出PicklingError

常见的方法

pickle.dump(obj, file, protocol=None, *, fix_imports=True)
复制代码

obj对象序列化到一个file文件中,该方法与Pickler(file, protocol).dump(obj)等价。

pickle.dumps(obj, protocol=None, *, fix_imports=True)
复制代码

obj对象序列化成bytes二进制数据。

pickle.load(file, *, fix_imports=True, encoding="ASCII", errors="strict")
复制代码

file文件中反序列化一个对象,该方法与Unpickler(file).load()等价。

pickle.loads(bytes_object, *, fix_imports=True, encoding="ASCII", errors="strict")
复制代码

从二进制数据bytes_object反序列化对象。

序列化例子

import pickle# 定义了一个包含了可以被序列化对象的字典
data = {'a': [1, 2.0, 3, 4 + 6j],'b': ("character string", b"byte string"),'c': {None, True, False}
}with open('data.pickle', 'wb') as f:# 序列化对象到一个data.pickle文件中# 指定了序列化格式的版本pickle.HIGHEST_PROTOCOLpickle.dump(data, f, pickle.HIGHEST_PROTOCOL)
复制代码

执行之后在文件夹中多一个data.pickle文件

serialization
├── data.pickle
├── pickles.py
└── unpickles.py
复制代码

反序列化例子

import picklewith open('data.pickle', 'rb') as f:# 从data.pickle文件中反序列化对象# pickle能够自动检测序列化文件的版本# 所以这里可以不用版本号data = pickle.load(f)print(data)# 执行后结果
# {'a': [1, 2.0, 3, (4+6j)], 'b': ('character string', b'byte string'), 'c': {False, True, None}}
复制代码

0x02 json

json是与语言无关,非常通用的数据交互格式。在Python它与marshalpickle一样拥有相似的API

常见的方法

json.dump(obj, fp, *, skipkeys=False, ensure_ascii=True, check_circular=True, allow_nan=True, cls=None, indent=None, separators=None, default=None, sort_keys=False, **kw)
复制代码

序列化对象到fp文件中

json.dumps(obj, *, skipkeys=False, ensure_ascii=True, check_circular=True, allow_nan=True, cls=None, indent=None, separators=None, default=None, sort_keys=False, **kw)
复制代码

obj序列化成json对象

json.load(fp, *, cls=None, object_hook=None, parse_float=None, parse_int=None, parse_constant=None, object_pairs_hook=None, **kw)
复制代码

从文件中反序列化成一个对象

json.loads(s, *, encoding=None, cls=None, object_hook=None, parse_float=None, parse_int=None, parse_constant=None, object_pairs_hook=None, **kw)
复制代码

json格式文档中反序列化成一个对象

jsonPython对象的转化对照表

JSONPython
objectdict
list,tuplearray
strstring
int, float, int- & float-derived Enumsnumber
Truetrue
Falsefalse
Nonenull

对于基本类型、序列、以及包含基本类型的集合类型json都可以很好的完成序列化工作。

序列化例子

>>> import json
>>> json.dumps(['foo', {'bar': ('baz', None, 1.0, 2)}])
'["foo", {"bar": ["baz", null, 1.0, 2]}]'
>>> print(json.dumps("\"foo\bar"))
"\"foo\bar"
>>> print(json.dumps('\u1234'))
"\u1234"
>>> print(json.dumps('\\'))
"\\"
>>> print(json.dumps({"c": 0, "b": 0, "a": 0}, sort_keys=True))
{"a": 0, "b": 0, "c": 0}
>>> from io import StringIO
>>> io = StringIO()
>>> json.dump(['streaming API'], io)
>>> io.getvalue()
'["streaming API"]'
复制代码

反序列化例子

>>> import json
>>> json.loads('["foo", {"bar":["baz", null, 1.0, 2]}]')
['foo', {'bar': ['baz', None, 1.0, 2]}]
>>> json.loads('"\\"foo\\bar"')
'"foo\x08ar'
>>> from io import StringIO
>>> io = StringIO('["streaming API"]')
>>> json.load(io)
['streaming API']
复制代码

对于object的情况就复杂一些了

例如定义了复数complex对象的json文档

complex_data.json

{"__complex__": true,"real": 42,"imaginary": 36
}
复制代码

要把这个json文档反序列化成Python对象,就需要定义转化的方法

# coding=utf-8
import json# 定义转化函数,将json中的内容转化成complex对象
def decode_complex(dct):if "__complex__" in dct:return complex(dct["real"], dct["imaginary"])else:return dctif __name__ == '__main__':with open("complex_data.json") as complex_data:# object_hook指定转化的函数z = json.load(complex_data, object_hook=decode_complex)print(type(z))print(z)# 执行结果
# <class 'complex'>
# (42+36j)
复制代码

如果不指定object_hook,那么默认将json文档中的object转成dict

# coding=utf-8
import jsonif __name__ == '__main__':with open("complex_data.json") as complex_data:# 这里不指定object_hookz2 = json.loads(complex_data.read())print(type(z2))print(z2)
# 执行结果
# <class 'dict'>
# {'__complex__': True, 'real': 42, 'imaginary': 36}
复制代码

可以看到json文档中的object转成了dict对象。
一般情况下这样使用似乎也没什么问题,但如果对类型要求很高的场景就需要明确定义转化的方法了。

除了object_hook参数还可以使用json.JSONEncoder

import jsonclass ComplexEncoder(json.JSONEncoder):def default(self, obj):if isinstance(obj, complex):# 如果complex对象这里转成数组的形式return [obj.real, obj.imag]# 默认处理return json.JSONEncoder.default(self, obj)if __name__ == '__main__':c = json.dumps(2 + 1j, cls=ComplexEncoder)print(type(c))print(c)# 执行结果
# <class 'str'>
# [2.0, 1.0]
复制代码

因为json模块并不是对所有类型都能够自动完成序列化的,对于不支持的类型,会直接抛出TypeError

>>> import datetime
>>> d = datetime.datetime.now()
>>> dct = {'birthday':d,'uid':124,'name':'jack'}
>>> dct
{'birthday': datetime.datetime(2019, 6, 14, 11, 16, 17, 434361), 'uid': 124, 'name': 'jack'}
>>> json.dumps(dct)
Traceback (most recent call last):File "<pyshell#19>", line 1, in <module>json.dumps(dct)File "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/json/__init__.py", line 231, in dumpsreturn _default_encoder.encode(obj)File "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/json/encoder.py", line 199, in encodechunks = self.iterencode(o, _one_shot=True)File "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/json/encoder.py", line 257, in iterencodereturn _iterencode(o, 0)File "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/json/encoder.py", line 179, in defaultraise TypeError(f'Object of type {o.__class__.__name__} '
TypeError: Object of type datetime is not JSON serializable
复制代码

对于不支持序列化的类型例如datetime以及自定义类型,就需要使用JSONEncoder来定义转化的逻辑。

import json
import datetime# 定义日期类型的JSONEncoder
class DatetimeEncoder(json.JSONEncoder):def default(self, obj):if isinstance(obj, datetime.datetime):return obj.strftime('%Y-%m-%d %H:%M:%S')elif isinstance(obj, datetime.date):return obj.strftime('%Y-%m-%d')else:return json.JSONEncoder.default(self, obj)if __name__ == '__main__':d = datetime.date.today()dct = {"birthday": d, "name": "jack"}data = json.dumps(dct, cls=DatetimeEncoder)print(data)# 执行结果
# {"birthday": "2019-06-14", "name": "jack"}
复制代码

现在我们希望发序列化时,能够将json文档中的日期格式转化成datetime.date对象,这时就需要使用到json.JSONDecoder了。

# coding=utf-8
import json
import datetime# 定义Decoder解析json
class DatetimeDecoder(json.JSONDecoder):# 构造方法def __init__(self):super().__init__(object_hook=self.dict2obj)def dict2obj(self, d):if isinstance(d, dict):for k in d:if isinstance(d[k], str):# 对日期格式进行解析,生成一个date对象dat = d[k].split("-")if len(dat) == 3:date = datetime.date(int(dat[0]), int(dat[1]), int(dat[2]))d[k] = datereturn dif __name__ == '__main__':d = datetime.date.today()dct = {"birthday": d, "name": "jack"}data = json.dumps(dct, cls=DatetimeEncoder)# print(data)obj = json.loads(data, cls=DatetimeDecoder)print(type(obj))print(obj)# 执行结果
# {"birthday": "2019-06-14", "name": "jack"}
# <class 'dict'>
# {'birthday': datetime.date(2019, 6, 14), 'name': 'jack'}
复制代码

0x03 总结一下

Python常见的序列化工具有marshalpicklejsonmarshal主要用于Python.pyc文件,并与Python版本相关。它不能序列化用户定义的类。 picklePython对象的序列化工具则比marshal更通用些,它可以兼容Python的不同版本。json是一种语言无关的数据结构,广泛用于各种网络应用尤其在REST API的服务中的数据交互。

0x04 学习资料

  • docs.python.org/3/library/m…
  • docs.python.org/3/library/p…
  • docs.python.org/3/library/j…

转载于:https://juejin.im/post/5d0362755188255e780b6815

相关文章:

TEE(Trusted Execution Environment)简介

TEE(Trusted Execution Environment)&#xff0c;可信执行环境&#xff0c;该环境可以保证不被常规操作系统干扰的计算&#xff0c;因此称为”可信”。这是通过创建一个可以在TrustZone的”安全世界”中独立运行的小型操作系统实现的&#xff0c;该操作系统以系统调用(由TrustZ…

自动驾驶关键环节:行人的行为意图建模和预测(上)

作者 | 黄浴出品 | AI科技大本营&#xff08;ID:rgznai100&#xff09;【导读】介绍一下最近行人行为意图建模和预测的研究工作&#xff0c;还是分上下两部分&#xff0c;本文为上半部分。Social LSTM: Human Trajectory Prediction in Crowded Spaces比较早的是斯坦福大学 201…

自定义windows下自动清除文件夹或者文件的只读属性的脚本

脚本内容入下&#xff1a;其中脚本中 ”/d"作用 &#xff08;可以用来改变当前驱动器目录&#xff09;例如&#xff1a; 我现在是在D盘&#xff0c;现在我要切换到C:\windows目录 脚本参数中 ATTRIB -R /S /D 解释内容如下&#xff1a;&#xff08;上述脚本参数中的 cd …

C++11容器中新增加的emplace相关函数的使用

C11中&#xff0c;针对顺序容器(如vector、deque、list)&#xff0c;新标准引入了三个新成员&#xff1a;emplace_front、emplace和emplace_back&#xff0c;这些操作构造而不是拷贝元素。这些操作分别对应push_front、insert和push_back&#xff0c;允许我们将元素放置在容器头…

Silverlight+WCF 新手实例 象棋 主界面-棋谱-获取列表(三十八)

2019独角兽企业重金招聘Python工程师标准>>> 在线演示地址&#xff1a;SilverlightWCF 新手实例 象棋 在线演示 在SilverlightWCF 新手实例 象棋 主界面-棋谱-布局写谱(三十六)中&#xff0c;我们完成下棋双方的棋谱显示&#xff0c;这节&#xff0c;我们为观众增加…

确认!语音识别大牛Daniel Povey将入职小米,曾遭霍普金斯大学解雇,怒拒Facebook

整理 | 夕颜 出品 | AI科技大本营&#xff08;ID:rgznai100&#xff09; 【导读】10 月 17 日&#xff0c;语音界传奇 Daniel Povey 发布推特&#xff0c;宣布自己 2019 年末将要入职小米&#xff0c;目前正在签订合同阶段&#xff0c;入职后&#xff0c;他将带领一支团队研发…

软链接与硬链接

$ ln f1 f2 #创建f1的一个硬连接文件f2$ ln -s f1 f3 #创建f1的一个符号连接文件f3$ ls -li # -i参数显示文件的inode节点信息转载于:https://www.cnblogs.com/zhizouxiao/p/3794668.html

一文读懂Python复杂网络分析库networkx | CSDN博文精选

作者 | yyl424525来源 | CSDN博客文章目录1. 简介安装支持四种图绘制网络图基本流程2. Graph-无向图节点边属性有向图和无向图互转3. DiGraph-有向图一些精美的图例子环形树状图权重图Giant ComponentRandom Geometric Graph 随机几何图节点颜色渐变边的颜色渐变Atlas画个五角星…

C++11多线程中std::call_once的使用

C11中的std::call_once函数位于<mutex>头文件中。在多线程编程中&#xff0c;有时某个任务只需要执行一次&#xff0c;此时可以用C11中的std::call_once函数配合std::once_flag来实现。如果多个线程需要同时调用某个函数&#xff0c;std::call_once可以保证多个线程对该函…

Solaris 上网配置

2019独角兽企业重金招聘Python工程师标准>>> 早上装solaris10系统的时候&#xff0c;没选默认&#xff0c;选了desk-session模式安装。全英文无界面安装&#xff0c;中间还跑出几个乱码。 靠着随便选随便F2&#xff0c;终于安装完了。 就在那设完分辨率后&#xff0…

Configure,Makefile.am, Makefile.in, Makefile文件之间关系

为什么80%的码农都做不了架构师&#xff1f;>>> 1.autoscan (autoconf): 扫描源代码以搜寻普通的可移植性问题&#xff0c;比如检查编译器&#xff0c;库&#xff0c;头文件等&#xff0c;生成文件configure.scan,它是configure.ac的一个雏形。 your source files…

这款耳机一点不输千元级的AirPods

你如果问我&#xff1a;生活中你觉得必不可少的一件电子产品是什么&#xff1f;那么我会毫不犹豫的回答你&#xff1a;是耳机&#xff01;出门忘带耳机是绝对不能忍听不听没关系&#xff0c;但是有它比较安心我觉得生活中不仅是我很多人都对耳机有一种依赖因为很多人都喜欢音乐…

CUDA Samples: Image Process: BGR to Gray

在图像处理中&#xff0c;颜色变换BGR到Gray&#xff0c;常见的一般有两种计算方式&#xff0c;一种是基于浮点数计算&#xff0c;一种是基于性能优化的通过移位的整数计算。浮点数计算公式为&#xff1a; gray 0.1140 * B 0.5870 * G 0.2989 * R;整数计算公式为&#xff1…

CYQ.Data 数据框架系列索引

2019独角兽企业重金招聘Python工程师标准>>> 索引基础导航&#xff1a; 1&#xff1a;下载地址&#xff1a;http://www.cyqdata.com/download/article-detail-426 2&#xff1a;入门教程&#xff1a;http://www.cyqdata.com/cyqdata/article-cate-33 3&#xff1a;购…

Tesseract 3 语言数据的训练方法

OCR,光学字符识别 光学字符识别(OCR,Optical Character Recognition)是指对文本资料进行扫描&#xff0c;然后对图像文件进行分析处理&#xff0c;获取文字及版面信息的过程。OCR技术非常专业&#xff0c;一般多是印刷、打印行业的从业人员使用&#xff0c;可以快速的将纸质资料…

Windows C++中__declspec(dllexport)的使用

__declspec是Microsoft VC中专用的关键字&#xff0c;它配合着一些属性可以对标准C/C进行扩充。__declspec关键字应该出现在声明的前面。 __declspec(dllexport)用于Windows中的动态库中&#xff0c;声明导出函数、类、对象等供外面调用&#xff0c;省略给出.def文件。即将函数…

图灵奖得主LeCun力推无监督学习:要重视基于能量的学习方法

作者 | Tiernan Ray译者 | 夕颜出品 | AI科技大本营&#xff08;ID:rgznai100&#xff09;导语&#xff1a;图灵奖得主深度学习大牛 Yann LeCun 表示&#xff0c;人工智能的下一个发展方向可能是放弃深度学习的所有概率技巧&#xff0c;转而掌握一系列转移能量值的方法。据说&a…

html5小游戏Untangle

2019独角兽企业重金招聘Python工程师标准>>> 今天介绍一个HTML5的小游戏&#xff0c;让大家体验到HTML5带来的乐趣。这个小游戏很简单&#xff0c;只要用鼠标拖动 蓝点&#xff0c;让图上的所有线都不相交&#xff0c;游戏时间就会停止&#xff0c;是动用大家头脑的…

【VMCloud云平台】SCCM(四)域内推送代理

继上一篇云平台完成SCCM部署篇之后&#xff0c;SCCM篇正式开始&#xff0c;今天将开始介绍SCCM为域内机器推送代理&#xff08;紫色为完成实施&#xff0c;红色为实施中&#xff09;&#xff1a; 1、 点击站点&#xff1a; 2、 右键属性&#xff0c;点击客户端安装设置&#…

Python实现决策树(Decision Tree)分类

关于决策树的简介可以参考&#xff1a; http://blog.csdn.net/fengbingchun/article/details/78880934在 https://machinelearningmastery.com/implement-decision-tree-algorithm-scratch-python/ 中给出了CART(Classification and Regression Trees,分类回归树算法,简称CART…

顶尖技术专家严选,15场前沿论坛思辨,2019中国大数据技术大会邀您共赴

扫码了解2019中国大数据技术大会&#xff08;https://t.csdnimg.cn/IaHb&#xff09;更多详情。2019中国大数据技术大会&#xff08;BDTC 2019&#xff09;将于12月5日-7日在北京长城饭店举办&#xff0c;本届大会将聚焦智能时代&#xff0c;大数据技术的发展曲线以及大数据与社…

jQuery 加法计算 使用+号即强转类型

1 var value1 $("#txt1").val(); 2 var value2 $("#txt2").val(); 3 //数值前添加号 number加号和数值加号需要用空格隔开 即实现加法运算 4 $("#txt3").val(value1 value2); 转载于:https://www.cnblogs.com/xiemin-minmin/p/11026784.…

Android Volley 库通过网络获取 JSON 数据

本文内容 什么是 Volley 库 Volley 能做什么 Volley 架构 环境 演示 Volley 库通过网络获取 JSON 数据 参考资料 Android 关于网络操作一般都会介绍 HttpClient 以及 HttpConnection 这两个包。前者是 Apache 开源库&#xff0c;后者是 Android 自带 API。企业级应用&#xff0…

​哪些开发问题最让程序员“头秃”?我们分析了Stack Overflow的11000个问题

作者 | Nick Roberts编译 | AI科技大本营&#xff08;ID:rgznai100&#xff09;自 2008 年成立以来&#xff0c;Stack Overflow 一直在拯救所有类型的开发人员。自那时以来&#xff0c;开发人员提出了数百万个关于开发领域的问题。但是&#xff0c;迫使开发者转向 Stack Overfl…

OpenCV3.3中决策树(Decision Tree)接口简介及使用

OpenCV 3.3中给出了决策树Decision Tres算法的实现&#xff0c;即cv::ml::DTrees类&#xff0c;此类的声明在include/opencv2/ml.hpp文件中&#xff0c;实现在modules/ml/src/tree.cpp文件中。其中&#xff1a;(1)、cv::ml::DTrees类&#xff1a;继承自cv::ml::StateModel&…

ARM 寄存器 和 工作模式了解

一. ARM 工作模式 1. ARM7&#xff0c;ARM9&#xff0c;ARM11&#xff0c;处理器有 7 种工作模式&#xff1b;Cortex-A 多了一个监视模式&#xff08;Monitor&#xff09; 2. 用户模式&#xff1a;非特权模式&#xff0c;大部分任务执行在这种模式&#xff0c;它运行在操作系…

英文版PDF不能显示中文PDF文件的解决方法

首先&#xff0c;PDF如果是英文版本的话&#xff0c;先装一个与之对应的PDF中文包。装上之后要检查的两项&#xff1a;1、PDF本身打开Adobe pdf选择“edit”"Preference""Internet"将"internet"下的三个勾全部勾上"OK"2、IE设置打开IE…

Linux下__attribute__((visibility (default)))的使用

在Linux下动态库(.so)中&#xff0c;通过GCC的C visibility属性可以控制共享文件导出符号。在GCC 4.0及以上版本中&#xff0c;有个visibility属性&#xff0c;可见属性可以应用到函数、变量、模板以及C类。 限制符号可见性的原因&#xff1a;从动态库中尽可能少地输出符号是一…

java web学习项目20套源码完整版

java web学习项目20套源码完整版 自己收集的各行各业的都有&#xff0c;这一套源码吃遍所有作业项目&#xff01; 1、BBS论坛系统(jspsql)2、ERP管理系统&#xff08;jspservlet&#xff09;3、OA办公自动化管理系统&#xff08;Struts1.2Hibernate3.0Spring2DWR&#xff09;4、…

360金融携手上海交大共建AI实验室,开启人才战略新布局

10月16日&#xff0c;上海交通大学计算机科学系—360金融人工智能联合实验室成立仪式在上海交通大学闵行校区举行&#xff0c;联合实验室致力于AI技术在新金融领域的应用探索。成立仪式上&#xff0c;360金融CEO吴海生宣布了“未来科学家”计划&#xff0c;这是360金融在人工智…