json & pickle模块

1. 什么是序列化

  • 序列化是指把内存的数据类型转换成一个特定的格式内容,该格式的内容可用于存储或者传输给其他平台使用

  • 内存中的数据类型——>序列化——>特定的格式(json格式或者pickle格式)

  • 内存中的数据类型<——反序列化<——特定的格式(json格式或者pickle格式)

'''
{'aaa': 111}——>序列化str({'aaa': 111})——>"{'aaa':111}"
{'aaa': 111}<——反序列化eval("{'aaa':111}")<——"{'aaa':111}"
'''

2. 为何要序列化

  • 序列化得到结果——>特定的格式的内容有两种用途

  • 1、可用于存储===>用于存档

  • 2、传输给其他平台使用===>跨平台数据交互

'''
python                  java
 列表       特定的格式     数组
 
 
 强调:
     针对用途1的特定格式:可以是一种专用的格式——> pickle只有python可以识别
     针对用途2的特定格式:应该是一种通用的,能够被所有语言识别的格式——> json
'''

3. 序列化与反序列化的使用

# 序列化
import json

# 序列化的复杂方法
json_res = json.dumps([1, 'aa', True, False, [1, 2, 3], {'b': 11}])
with open(r'test.json', 'wt', encoding='utf-8') as f:
    f.write(json_res)

# 序列化简单方法
with open(r'test.json', 'wt', encoding='utf-8') as f:
    json.dump([1, 'aa', True, False, [1, 2, 3], {'b': 11}], f)

# 反序列化
# 反序列化的复杂方法
with open(r'test.json', 'rt', encoding='utf-8') as f:
    json_res = f.read()
    loads_res = json.loads(json_res)
    print(loads_res)

# 反序列化的简单方法
with open(r'test.json', 'rt', encoding='utf-8') as f:
    loads_res = json.load(f)
    print(loads_res)

# json验证:json格式兼容的是所有语言通用的数据类型,不能使用独有的数据类型
json.dumps({1,2,3})  # 集合为python独有数据类型

#  json强调:一定要搞清楚json格式,不能与python混淆
l = json.loads('[1, "aaa", true, false]')
print(l)  # 结果:[1, 'aaa', True, False]

# 在python解释器2.7与3.6之后都可以json.loads(bytes类型),但唯独3.5不可以
res=json.dumps({'name':'哈哈哈'})
print(res,type(res))

res=json.loads('{"name": "\u54c8\u54c8\u54c8"}')
print(res,type(res))

4. 猴子补丁与ujson

  • 4.1 什么是猴子补丁

    • 猴子补丁的核心就是用自己的代码替换所用模块的源代码
  • 4.2 猴子补丁的功能(一切皆对象)

    • 拥有在模块运行时替换的功能, 例如: 一个函数对象赋值给另外一个函数对象(把函数原本的执行的功能给替换了)
  • 4.3 monkey patch的应用场景
'''
如果我们的程序中已经基于json模块编写了大量代码了,发现有一个模块ujson比它性能更高,
但用法一样,我们肯定不会想所有的代码都换成ujson.dumps或者ujson.loads,那我们可能
会想到这么做
'''
import ujson as json,但是这么做的需要每个文件都重新导入一下,维护成本依然很高
此时我们就可以用到猴子补丁了
只需要在入口处加上
, 只需要在入口加上:

import json
import ujson

def monkey_patch_json():
    json.__name__ = 'ujson'
    json.dumps = ujson.dumps
    json.loads = ujson.loads

monkey_patch_json() # 之所以在入口处加,是因为模块在导入一次后,后续的导入便直接引用第一次的成果

#其实这种场景也比较多, 比如我们引用团队通用库里的一个模块, 又想丰富模块的功能, 除了继承之外也可以考虑用Monkey
Patch.采用猴子补丁之后,如果发现ujson不符合预期,那也可以快速撤掉补丁。个人感觉Monkey
Patch带了便利的同时也有搞乱源代码的风险!

5. pickle模块

import pickle

res = pickle.dumps({1, 2, 3, 4, 5})
print(res, type(
    res))  # b'\x80\x04\x95\x0f\x00\x00\x00\x00\x00\x00\x00\x8f\x94(K\x01K\x02K\x03K\x04K\x05\x90.' <class 'bytes'>
res1 = pickle.loads(res)
print(res1, type(res1))  # {1, 2, 3, 4, 5} <class 'set'>

# pickle的序列化与反序列化
f = open('序列化对象_pickle', 'wb')  # 注意是w是写入str,wb是写入bytes,j是'bytes'
f.write(j)  # ------------------等价于pickle.dump(dic,f)

f.close()

# 反序列化
import pickle

f = open('序列化对象_pickle', 'rb')

data = pickle.loads(f.read())  # 等价于data=pickle.load(f)

print(data['age'])

# 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)

 

posted @ 2020-12-31 16:45  Avery_W  阅读(49)  评论(0)    收藏  举报