python学习之路(十一)
这一节主要讲一下【json and pickle】
先说一个例子
假如打游戏 你花好长时间养了一个小怪兽 然后你中午去吃饭
你没法砍别人了 怕别人给你的小怪兽砍死 但是你又不想退出
因为你得养着那个小怪兽 那怎么办? —— 挂机
就是你先给它挂起 就是当前这个环境 然后多少滴血
多少有多少宝贝 神马神马滴 。。。 kua cha 就挂起了
就跟暂停了差不多 然后吃饭回来再给它恢复
恢复之后又开始相互砍 就运行起来了
那还有可以举虚拟机的例子
虚拟机 它就可以暂停 挂起 然后它也可以恢复
之前哪个页面 哪个终端 哪个路径 神马神马滴 。。。
这个是怎么实现的呢?
它肯定是中断的时候 保存了一个什么东西
它保存在哪里? —— 全都保存在文件里面 对 文件
因为虚拟机运行 是在内存运行的 保存文件的时候
是从内存里面 把状态数据拷贝一个镜像 放到磁盘上面
内存里面的东西 它不仅仅是字符串 它可以有其它的数据类型
比如 字典 列表 函数 类 这些东西
但是保存在文件里 文件它只能保存字符串 或者说是二进制码
f = open('file.txt', 'w')
info = {
'name':'lucia',
'age':18
}
f.write(info)
f.close()
这段代码 它先 open 一个文件 f
然后有一个字典 info
把字典写入文件 —— 报错:
报错意思是 write 到文件 必须是 str 不能是 dict
那这个好办 —— 强制转换成字符串:
f.write(str(info))
然后代码不报错了 而且也存进去了:就是说 文件它只能保存字符串 不能存字典神马神马滴
存进去之后 还要恢复才行
现在把一个内存里面的字典的数据类型 变成字符串
然后存到了磁盘上 —— 这个过程叫做序列化
有序列化 就肯定有反序列化 —— 就是在加载回内存里面
在一个新的程序里面 打开刚才那个文件
f = open('file.txt', 'r')
然后读进来
data = f.read()
print(data)
读进来还不是最终目的 因为它是以字符串形式读进来的 没办法操作
还记得那个 eval 吧
data = eval(f.read())
这样子 确实是可以解决问题的那还有没有其它办法呢?
因为除了 eval 之外 还有更通用 更标准 更规范的办法
—— 就是反序列化 json
它序列化的时候 要写到文件 但并不是像 str 那样强制转换的
f.write(json.dumps(info))
这样子的然后反序列化的时候 再 import json
data = json.loads(f.read())
这样子 就反序列化到内存里面去了所以序列化是 dumps 反序列化是 loads
内存 --- 磁盘 --- 内存
运行 --- 挂起 --- 运行
就这个过程 很简单 容易理解
毕竟 现在从内存挂起 和从磁盘恢复的 只是一个字典
如果是 函数 又会怎样
import json
def sayhi(name):
print('hello, ', name)
info = {
'name':'lucia',
'job':'it',
'func':sayhi
}
f = open('lucia_de_file', 'w')
f.write(json.dumps(info))
f.close()
这样子会触发报错:TypeError: Object of type 'function' is not JSON serializable
意思是:函数类型 不是可序列化的类型
所以 json 它只能处理简单的数据类型 字典啊 列表啊 字符串啊 这些简单的
原因是 json 是在各种语言之间通用的 它负责各种语言之间的数据交互
就比方说 python 程序要和 java 程序交互 和 PHP 程序交互 等等
交互的时候 把 Python 的字典转成 Java 的字典
把 Java 的列表转成 Python 的列表
所以 不可以太复杂 只能是简单的
再说一句 xml 它正在逐渐被 json 取代
因为 xml 它主要的作用 也是在语言之间完成数据交互
但是 json 的好处在于 它看上去很容易看懂 很清晰
并且 不需要额外的标签之类的东西 来做很多的描述
最终 xml 必将被 json 完全取代
但是不管是 xml 还是 json 能处理的 都是简单的类型
那如果就是要处理复杂的类型怎么办
那就不是 json 了 换成 pickle 用法完完全全一样 就行了
import pickle
f = open('lucia_de_file', 'wb')
f.write(pickle.dumps(info))
运行就没有毛病 正常生成了 lucia_de_file然后反序列化 也是 pickle
import pickle
f = open('lucia_de_file', 'rb')
data = pickle.loads(f.read())
print(data)
这样子 遭遇的报错是:
AttributeError: Can't get attribute 'sayhi' on <module '__main__' from '/Users/lucia_gaga/PycharmProjects/practice_lucia/222.py'>
这个原因是 你需要把函数的内存地址 反序列化到内存中去但是刚才序列化的时候 得到的内存地址 没了
运行完了 就没了 所以根本就不应该这样写反序列化的代码
把 sayhi 函数的代码 拷贝过来 它的内存地址就不会丢了:
这样子 就完成了反序列化
还有一种写法是
pickle.dump(info, f)
以及
pickle.load(f)
序列化一次 & 反序列化一次
f.write(json.dumps(info))
info['job'] = 'qa'
f.write(json.dumps(info))
两次序列化之间 改一个值 然后结果:然后再看反序列化:
会报错
它的意思是 只能 dump 一次 然后 load 一次 不能多次
还记得虚拟机快照吗
它其实是 每个镜像保存为一个文件 而不是一个文件里面放好多内容