json与pickle模块
序列化与反序列化
序列化指的是把内存的数据类型转换成一个特定格式的内容,该格式的内容可用于存储或者传输给其他平台使用。
- 内存中的数据--->序列化--->特定的格式的字符串或bytes类型。
- 特定的格式字符串或bytes类型--->反序列化--->内存中的数据。
序列化的用途
序列化得到的特定格式内容有两种用途
- 1.可用于存储。
- 2.传输给其他平台使用 => 跨平台数据交互。
针对用途1的格式:
- 可以是一种专用的格式,只有Python可以识别 => pickle 格式
针对用途2的格式:
- 应该是一种通用、能够被所用语言识别的格式 => json 格式
json模块
- json.dumps():序列化
import json
res = json.dumps([1,'abc',True])
print(res,type(res))
[1, "abc", true] <class 'str'> 单引号变双引号
# 将序列化的内容写入文件
with open('test.txt',mode='wt',encoding='utf-8') as f:
res = json.dumps([1,'abc',True])
f.write(res)
- json.loads():反序列化
li = json.loads(res)
print(li,type(li))
[1, 'abc', True] <class 'list'>
# 双引号会变为单引号
# 将写入文件的内容读出并反序列化
with open('test.txt',mode='r',encoding='utf-8') as f:
res1 = json.loads(f.read())
print(res1,type(res1))
[1, 'abc', True] <class 'list'>
注意:在python解释器2.7与3.6之后都可以json.loads(bytes类型),但唯独3.5不可以。
>>> import json
>>> json.loads(b'{"a":111}')
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/Users/linhaifeng/anaconda3/lib/python3.5/json/__init__.py", line 312, in loads
s.__class__.__name__))
TypeError: the JSON object must be str, not 'bytes'
json.dump(date,file_obj):将传进去的date序列化为JSON格式后写入文件对象file_obj。
>>> import json
>>> with open('a.txt',mode='wt',encoding='utf-8') as f:
... json.dump([True,None,"abc"],f)
[true, null, "abc"]
json.load(file_obj):读取文件内容将其反序列化,返回反序列化后的内容。
>>> with open('a.txt',mode='rt',encoding='utf-8') as f:
... res = json.load(f)
...
>>> res
[True, None, 'abc']
json格式序列化后与原数据类型的区别:
原数据格式 | JSON |
---|---|
True | true |
False | false |
None | null |
'abc' | "abc" |
JSON序列化默认支持的对象和类型:
Python | JSON |
---|---|
dict | object |
list, tuple | array |
str | string |
int, float, int 和 float 派生的枚举 | number |
True | true |
False | false |
None | null |
反序列化支持的对象和类型:
JSON | Python |
---|---|
object | dict |
array | list |
string | str |
number (int) | int |
number (real) | float |
true | True |
false | False |
null | None |
pickle模块:
模块 pickle
实现了对一个 Python 对象结构的二进制序列化和反序列化。
pickle
模块并不安全。你只应该对你信任的数据进行unpickle操作,构建恶意的 pickle 数据来在解封时执行任意代码是可能的。绝对不要对不信任来源的数据和可能被篡改过的数据进行解封。考虑使用 hmac
来对数据进行签名,确保数据没有被篡改。
pickle.dumps():序列化。
import pickle
res = pickle.dumps({1,2,3,4,5,'a'}
print(res,type(res))
# b'\x80\x04\x95\x13\x00\x00\x00\x00\x00\x00\x00\x8f\x94(K\x01K\x02K\x03K\x04K\x05\x8c\x01a\x94\x90.' <class 'bytes'>
pickle.loads():反序列化。
res1 = pickle.loads(res)
print(res1,type(res1))
# {1, 2, 3, 4, 5, 'a'} <class 'set'>
pickle.dump(obj,file):将对象 obj 封存以后的对象写入已打开的file文件对象。
with open('a.txt',mode='wb') as f:
pickle.dump({'k1':None,"k2":'abc'},f)
pickle.load(f):从已打开的文件 中读取封存后的对象,重建其中特定对象的层次结构并返回。
with open('a.txt',mode='rb') as f:
res = pickle.load(f)
print(res)
{'k1': None, 'k2': 'abc'}
注意:pickle序列化后的内容为bytes类型,所以打开文件必须要为b模式。
- Python2与Python3的pickle兼容性问题。
# coding:utf-8
import pickle
with open('a.pkl',mode='wb') as f:
# 一:在python3中执行的序列化操作如何兼容python2
# python2不支持protocol>2,默认python3中protocol=4
# 所以在python3中dump操作应该指定protocol=2
pickle.dump('你好啊',f,protocol=2)
with open('a.pkl', mode='rb') as f:
# 二:python2中反序列化才能正常使用
res=pickle.load(f)
print(res)
- Pickle的问题和所有其他编程语言特有的序列化问题一样,就是它只能用于Python,并且可能不同版本的Python彼此都不兼容,因此,只能用Pickle保存那些不重要的数据,不能成功地反序列化也没关系。
json与pickle区别
- JSON 是一个文本序列化格式(它输出 unicode 文本,尽管在大多数时候它会接着以
utf-8
编码),而 pickle 是一个二进制序列化格式; - JSON 是可以直观阅读的,而 pickle 不是;
- JSON是可互操作的,在Python系统之外广泛使用,而pickle则是Python专用的;
- 默认情况下,JSON 只能表示 Python 内置类型的子集,不能表示自定义的类;但 pickle 可以表示大量的 Python 数据类型(可以合理使用 Python 的对象内省功能自动地表示大多数类型,复杂情况可以通过实现 specific object APIs 来解决)。
- 不像pickle,对一个不信任的JSON进行反序列化的操作本身不会造成任意代码执行漏洞。
参考文档:
https://docs.python.org/zh-cn/3/library/json.html?highlight=json#module-json