序列化
将原本的字典、列表等格式的内容转换成一个字符串的过程。程序间的数据传递需要一定的规范格式,序列化,反序列化做的就是这件事。
将字典转换成一个字符串很简单,str(dic) 就可以办到,为什么还要又序列化模块呢?
的确,str(dic) 就可以完成字典到字符串的转换,但是怎样才能把字符串转换为字典还没解决,eval() 可以,将一个字符串类型的字典str_dic给eval,就可以得到一个返回的字典类型。这看似很好,其实有着安全隐患,eval的功能是将字符串str当作有效的表达式来求值并返回计算结果。试想如果从文件中读出的不是一个简单的数据结构,而是一句类似删除文件的破坏性语句,那么后果gg....所以,不推荐eval方法进行反序列化操作(str --> python中的数据类型)
Python中 json、pickle以及itsdangerous 都具备序列化功能,下面我们一一来看:
一、json中的json.dumps和json.loads:
- 序列化:json.dumps() 将一个Python数据类型进行json格式的编码解析(dict转成str)
- 反序列化:json.loads() 将json格式的基于字典的字符串转换成Python数据类型(str转成dict)
import json
data_dict = {"name": "xxx", "gender": "female"}
# <class 'dict'>
print(type(data_dict))
data_str = json.dumps(data_dict)
# <class 'str'>
print(type(data_str))
data_dict_1 = json.loads(data_str)
# <class 'dict'>
print(type(data_dict_1))
扩展:
json.loads和json.load,json.dumps和json.dump的区别
json.dump是将python数据保存成json。主要配合json.load来使用。
- json.dump(x,f),x是对象,f是文件对象,将json数据写入到f文本文件当中。
- json.load是读取json数据 。主要配合json.dump来使用。
import json
data_dict = {"name": "xxx", "gender": "female"}
f = open('xxx.txt', 'w')
json.dump(data_dict, f)
# 这样就生成了一个xxx.txt文件,保存了json格式的数据
# json.load加载json格式文件
f = open('xxx.txt', 'r')
data = json.load(f)
# 输出读取的数据
print(data)
二、pickle中的pickle.dumps和pickle.loads:
- pickle.dumps(): 将obj对象序列化并返回一个bytes对象(某一个数据类型转成bytes)
- pickle.loads(): 将bytes反序列化并返回一个对象(bytes转成之前的数据类型)
import pickle
data_dict = {"name": "xxx", "gender": "female"}
data_dumps = pickle.dumps(data_dict)
# <class 'bytes'>
print(type(data_dumps))
data_loads = pickle.loads(data_dumps)
# <class 'dict'>
print(type(data_loads))
扩展:
pickle.loads和pickle.load,pickle.dumps和pickle.dump的区别
- pickle.dump()方法将obj对象序列化为字节(bytes)写入到file文件中
- pickle.load()从一个对象文件中读取序列化数据,将其反序列化之后返回一个对象
f = open('xxx.txt', 'wb')
pickle.dump(data_dict, f)
data = pickle.load('xxx.txt')
f.close()
三、itsdangerous中的itsdangerous.dumps和itsdangerous.loads:
序列化
因为字符串难以处理,本模块也提供了一个与json或pickle类似的序列化接口。(它内部默认使用simplejson,但是可以通过子类进行修改)
:class:`Serializer`类实现了:
>>> from itsdangerous import Serializer
>>> s = Serializer('secret-key')
>>> s.dumps([1, 2, 3, 4])
'[1, 2, 3, 4].r7R9RhGgDPvvWl3iNzLuIIfELmo'
它当然也可以加载数据:
>>> s.loads('[1, 2, 3, 4].r7R9RhGgDPvvWl3iNzLuIIfELmo')
[1, 2, 3, 4]
from itsdangerous import TimedJSONWebSignatureSerializer as Serializer
@staticmethod
def generate_save_user_token(openid):
# """
# 生成保存用户数据的token
# :param openid: 用户的openid
# :return: token
# """
serializer = Serializer(settings.SECRET_KEY, expires_in=contents.SAVE_QQ_USER_TOKEN_EXPIRES)
data = {'openid': openid}
token = serializer.dumps(data)
return token.decode()
@staticmethod
def check_save_user_token(token):
# """
# 检验保存用户数据的token
# :param token: token
# :return: openid or None
# """
serializer = Serializer(settings.SECRET_KEY, expires_in=contents.SAVE_QQ_USER_TOKEN_EXPIRES)
try:
data = serializer.loads(token)
except BadData:
return None
else:
return data.get('openid')
json-pickle-itsdangerous对比总结:
1-pickle不是用于多种语言间的数据传输,它仅作为python对象的持久化,只针对python的数据类型;而json可以支持更多语言的序列化和反序列化,在python中序列化一个自定义的类对象时,会抛出一个 TypeError;
2-json的序列化输出是文本对象是str类型,而pickle序列化的输出是二进制字节-bytes
3-json可读性优于pickle。
4-itsdangerous也提供了一个与json或pickle类似的序列化接口。(它内部默认使用simplejson,但是可以通过子类进行修改)
5-pickle:就是将python数据转成原始的二进制数据;
itsdangerous:就是通过密钥secret-key进行加密处理。多用于生成token。
6-jsonify和json.dumps()
jsonify的作用实际上就是将我们传入的json形式数据序列化成为json字符串,作为响应的body,并且设置响应的Content-Type为application/json,构造出响应返回至客户端。jsonify的部分源码如下:
def jsonify(*args, **kwargs):
indent = None
if current_app.config['JSONIFY_PRETTYPRINT_REGULAR'] \
and not request.is_xhr:
indent = 2
return current_app.response_class(dumps(dict(*args, **kwargs),
indent=indent),
mimetype='application/json')
jsonify将dict类型转变为json对象。json.dumps只是将dict类型转化为str类型,并非一个json对象。
jsonify其实也是用dumps方法转换成了json格式的字符串,但是jsonify会根据http协议的body进行格式重新编排。而json.dumps只是单纯的将dict类型转化为str类型,可以直接return json.dumps(data)