关于我

一个有思想的程序猿,终身学习实践者,目前在一个创业团队任team lead,技术栈涉及Android、Python、Java和Go,这个也是我们团队的主要技术栈。

Github:https://github.com/hylinux1024

微信公众号:终身开发者(angrycode)

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_PROTOCOL
pickle.dump(data, f, pickle.HIGHEST_PROTOCOL)

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

serialization
├── data.pickle
├── pickles.py
└── unpickles.py

反序列化例子

import pickle

with 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对象的转化对照表

JSON Python
object dict
list,tuple array
str string
int, float, int- & float-derived Enums number
True true
False false
None null

对于基本类型、序列、以及包含基本类型的集合类型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 dct if __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 json if __name__ == '__main__': with open("complex_data.json") as complex_data:
# 这里不指定object_hook
z2 = 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 json

class 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 dumps
return _default_encoder.encode(obj)
File "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/json/encoder.py", line 199, in encode
chunks = self.iterencode(o, _one_shot=True)
File "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/json/encoder.py", line 257, in iterencode
return _iterencode(o, 0)
File "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/json/encoder.py", line 179, in default
raise 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] = date
return d if __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 学习资料

一文了解Python常见的序列化操作的更多相关文章

  1. Python常见数据类型及操作

    基础数据类型 什么是数据类型? 我们人类可以很容易的分清数字与字符的区别,但计算机并不能,计算机虽然很强大,但从某种角度上看又很傻,除非你明确的告诉它,1是数字,“汉”是文字,否则它是分不清1和‘汉’ ...

  2. Python常见字符串处理操作

    Python中字符串处理的方法已经超过37种了,下面是一些常用的字符串处理的方法,以后慢慢添加. >>> s = 'Django is cool' #创建一个字符串 >> ...

  3. Python 常见的字符串操作

    1.strip.lstrip和rstrip 描述: 用于移除字符串左右两边.左边.右边指定的字符(默认为空白符,例如:/n, /r, /t, ' ')或字符序列. 语法: str.strip([cha ...

  4. Python json.dumps 特殊数据类型的自定义序列化操作

    场景描述: Python标准库中的json模块,集成了将数据序列化处理的功能:在使用json.dumps()方法序列化数据时候,如果目标数据中存在datetime数据类型,执行操作时, 会抛出异常:T ...

  5. Asp.Net Core 2.0 项目实战(8)Core下缓存操作、序列化操作、JSON操作等Helper集合类

    本文目录 1.  前沿 2.CacheHelper基于Microsoft.Extensions.Caching.Memory封装 3.XmlHelper快速操作xml文档 4.Serializatio ...

  6. cPickle对python对象进行序列化,序列化到文件或内存

    pickle模块使用的数据格式是python专用的,并且不同版本不向后兼容,同时也不能被其他语言说识别.要和其他语言交互,可以使用内置的json包 cPickle可以对任意一种类型的python对象进 ...

  7. 从watevrCTF-2019:Pickle Store中学习python之pickle序列化漏洞

    从watevrCTF-2019:Pickle Store中学习python之pickle序列化漏洞 pickle提供了一个简单的持久化功能.可以将对象以文件的形式存放在磁盘上. 其本质是Picklin ...

  8. Python序列化操作与反序列操作

    一.概念 序列化:转向一个字符串数据类型序列:字符串 二.需要做序列化操作的情况1.数据存储2.网络上数据传输 从数据类型到字符串的过程叫序列化从字符串到数据类型的过程叫反序列化 三.现有序列化模块1 ...

  9. Python 常见文件操作的函数示例(转)

    转自:http://www.cnblogs.com/txw1958/archive/2012/03/08/2385540.html # -*-coding:utf8 -*- ''''' Python常 ...

随机推荐

  1. 机器学习-FP Tree

    接着是上一篇的apriori算法: FP Tree数据结构 为了减少I/O次数,FP Tree算法引入了一些数据结构来临时存储数据.这个数据结构包括三部分,如下图所示 第一部分是一个项头表.里面记录了 ...

  2. Spring Cloud Config 实现配置中心,看这一篇就够了

    Spring Cloud Config 是 Spring Cloud 家族中最早的配置中心,虽然后来又发布了 Consul 可以代替配置中心功能,但是 Config 依然适用于 Spring Clou ...

  3. docker原理介绍

    内部分享的ppt,做的有些粗糙... 个人使用的总结,如有错误,多多指正!

  4. springboot - 登录+静态资源访问+国际化

    1.项目目录结构 2.pom.xml <?xml version="1.0" encoding="UTF-8"?> <project xmln ...

  5. 牛客第十场Rikka with Prefix Sum

    由于其中的2操作非常多,我们就需要将其快速的更改,就会用到组合数的东西 其实自己手写一下就可以发现对于一个点增加的值在经过不断地前缀和累加过程中对于一点的贡献满足杨辉三角 所以我们就需要记录一下其中的 ...

  6. Java面向对象16种原则

    一   类的设计原则   1 依赖倒置原则-Dependency Inversion Principle (DIP) 2 里氏替换原则-Liskov Substitution Principle (L ...

  7. TCP拥塞算法瓶颈及TCP加速器解决方案

    TCP拥塞算法详解    ps:详解TCP拥塞算法就是为了说明瓶颈所在.   先解释一下概念: 拥塞:对网络中某一资源的需求超出了该资源所能提供的可用部分 拥塞窗口:以字节为单位,表示能通过的数据报的 ...

  8. kubernetes对接第三方认证

    kubernetes对接第三方认证 kubernetes离线安装包地址 概述 本文介绍如何使用github账户去关联自己kubernetes账户.达到如下效果: 使用github用户email作为ku ...

  9. UE4中UMG与C++交互 页面文本修改

    在UE4中,有两种方式创建ui,一种是使用slate的方式,一种是UMG,UMG是slate的封装,是一个可视化的ui编辑器.slate则是纯c++方式(之前实验过一次slate创建页面,代码相当麻烦 ...

  10. 极力推荐一个简单好用的C++JSON库

      极力推荐一个简单好用的C++JSON库CJsonObject,让使用json如使用C++原生的结构体那般方便,随心所欲.CJsonObject是个优秀的C++JSON库,也许会是你见过的最为简单易 ...