来源:自学PHP网 时间:2019-08-07 16:07 作者:小飞侠 阅读:次
[导读] 一篇文章了解Python中常见的序列化操作...
|
0x00 marshal marshal使用的是与Python语言相关但与机器无关的二进制来读写Python对象的。这种二进制的格式也跟Python语言的版本相关,marshal序列化的格式对不同的版本的Python是不兼容的。 marshal一般用于Python内部对象的序列化。 一般地包括:
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序列化的数据类型有:
如果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文件
反序列化例子
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.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)
# 执行结果
#
如果不指定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)
# 执行结果
#
可以看到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) # 执行结果 # 因为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 "
对于不支持序列化的类型例如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"}
#
0x03 总结一下 Python常见的序列化工具有marshal、pickle和json。marshal主要用于Python的.pyc文件,并与Python版本相关。它不能序列化用户定义的类。 pickle是Python对象的序列化工具则比marshal更通用些,它可以兼容Python的不同版本。json是一种语言无关的数据结构,广泛用于各种网络应用尤其在REST API的服务中的数据交互。 0x04 学习资料
好了,以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,谢谢大家对自学php网的支持。 |
自学PHP网专注网站建设学习,PHP程序学习,平面设计学习,以及操作系统学习
京ICP备14009008号-1@版权所有www.zixuephp.com
网站声明:本站所有视频,教程都由网友上传,站长收集和分享给大家学习使用,如由牵扯版权问题请联系站长邮箱904561283@qq.com