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文件读写的支持。这也是marshal对Python版本不兼容的原因。开发者如果要使用序列化/反序列化,那么应该使用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它与marshal和pickle一样拥有相似的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格式文档中反序列化成一个对象
json与Python对象的转化对照表
对于基本类型、序列、以及包含基本类型的集合类型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常见的序列化工具有marshal、pickle和json。marshal主要用于Python的.pyc文件,并与Python版本相关。它不能序列化用户定义的类。
pickle是Python对象的序列化工具则比marshal更通用些,它可以兼容Python的不同版本。json是一种语言无关的数据结构,广泛用于各种网络应用尤其在REST API的服务中的数据交互。
0x04 学习资料
- docs.python.org/3/library/m…
- docs.python.org/3/library/p…
- docs.python.org/3/library/j…
好了,以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,谢谢大家对的支持。
免责声明:本站资源来自互联网收集,仅供用于学习和交流,请遵循相关法律法规,本站一切资源不代表本站立场,如有侵权、后门、不妥请联系本站删除!
稳了!魔兽国服回归的3条重磅消息!官宣时间再确认!
昨天有一位朋友在大神群里分享,自己亚服账号被封号之后居然弹出了国服的封号信息对话框。
这里面让他访问的是一个国服的战网网址,com.cn和后面的zh都非常明白地表明这就是国服战网。
而他在复制这个网址并且进行登录之后,确实是网易的网址,也就是我们熟悉的停服之后国服发布的暴雪游戏产品运营到期开放退款的说明。这是一件比较奇怪的事情,因为以前都没有出现这样的情况,现在突然提示跳转到国服战网的网址,是不是说明了简体中文客户端已经开始进行更新了呢?
更新日志
- 凤飞飞《我们的主题曲》飞跃制作[正版原抓WAV+CUE]
- 刘嘉亮《亮情歌2》[WAV+CUE][1G]
- 红馆40·谭咏麟《歌者恋歌浓情30年演唱会》3CD[低速原抓WAV+CUE][1.8G]
- 刘纬武《睡眠宝宝竖琴童谣 吉卜力工作室 白噪音安抚》[320K/MP3][193.25MB]
- 【轻音乐】曼托凡尼乐团《精选辑》2CD.1998[FLAC+CUE整轨]
- 邝美云《心中有爱》1989年香港DMIJP版1MTO东芝首版[WAV+CUE]
- 群星《情叹-发烧女声DSD》天籁女声发烧碟[WAV+CUE]
- 刘纬武《睡眠宝宝竖琴童谣 吉卜力工作室 白噪音安抚》[FLAC/分轨][748.03MB]
- 理想混蛋《Origin Sessions》[320K/MP3][37.47MB]
- 公馆青少年《我其实一点都不酷》[320K/MP3][78.78MB]
- 群星《情叹-发烧男声DSD》最值得珍藏的完美男声[WAV+CUE]
- 群星《国韵飘香·贵妃醉酒HQCD黑胶王》2CD[WAV]
- 卫兰《DAUGHTER》【低速原抓WAV+CUE】
- 公馆青少年《我其实一点都不酷》[FLAC/分轨][398.22MB]
- ZWEI《迟暮的花 (Explicit)》[320K/MP3][57.16MB]