python中常用的序列化模块_Python 中的序列化模块

封面图片来源:沙沙野

序列化模块前面讲到解码编码的时候提过,网络数据传输只能通过 bytes 类型。而文件写入内容(不是指存储)既可以是 bytes,也可以是 string。这些操作都可以使用 eval 函数来还原数据类型的原型

编码与解码

dic = {"姓名": "张三", "爱好": ["喝酒", "玩游戏"]}

# 先把该字典转化成字符串

s = str(dic)

# 再对其进行编码

b = s.encode("utf-8")

print(b)

# 运行结果:

b"{'\xe5\xa7\x93\xe5\x90\x8d': '\xe5\xbc\xa0\xe4\xb8\x89', '\xe7\x88\xb1\xe5\xa5\xbd': ['\xe5\x96\x9d\xe9\x85\x92', '\xe7\x8e\xa9\xe6\xb8\xb8\xe6\x88\x8f']}"

# 解码

s1 = b.decode("utf-8")

print(s1, type(s1))

# 运行结果:

{'姓名': '张三', '爱好': ['喝酒', '玩游戏']}

# 把字符串形式的字典转化成真正的字典

dic1 = eval(s1)

print(dic1, type(dic1))

# 运行结果:

{'姓名': '张三', '爱好': ['喝酒', '玩游戏']}

3. 实际操作中如果在网络传输过程使用 eval 函数并不安全,比如下面示例使用 input() 的本意是让用户输入姓名,假设用户别有用心,而你又使用了 eval 函数的话,那就很危险

name = input("请输入姓名: ")

ret = eval(name)

print(ret) # 这里的 print() 可以假设是返回给用户的内容

# 运行结果:

请输入姓名: __import__("os").system("dir")

定时任务.md test.log 工作记录.md

Python笔记 安装必备软件.md test01.py

定时任务.md

0

4. 上面的运行结果就是本 py 文件目录下的所有文件,都会返回给用户。这样用户就知道我这个目录下的所有信息,还能进一步处理,比如他要读取我 test.log 里面的内容

# 再次运行结果:

请输入姓名: open("test.log").read()

2019-11-13 15:13:55,783 test01.py [line:14] WARNING Warning message...

2019-11-13 15:13:55,783 test01.py [line:15] ERROR Error message...

2019-11-13 15:13:55,783 test01.py [line:16] CRITICAL Critical message...

5. 此时发现他已经获取到了我文件中的内容,然后他又想恶意删掉我的这个文件

# 重新运行结果:

请输入姓名: __import__("os").system("rm test.log")

# 注:"rm test.log" 在 Linux 系统下才有效;

# 如果是 Windows 系统,使用 "del test.log/q"

# 其中 "/q" 表示静音状态,不提示确认删除,这样你就察觉不到他的恶意操作了

# 查看目录下的所有文件,发现 test.log 文件已经没了

6. 上面提到 eval() 是不安全的,那么需要一个功能支持将数据安全传输到网络上。在此之前,先了解两个概念:序列化过程和反序列化过程序列化过程:将数据(数据结构,非字符串)转化成特殊的字符串(可以用于网络传输)

反序列化过程:将这个特殊的字符串转化成原来的数据结构

7. Python 中的序列化模块json 模块json 序列化模块是所有语言通用的一种标准,也是一种数据转化格式

也就是说比如 Python 中的字典,可以通过 json 模块转化成 bytes 来进行网络传输成 java 的字典

可以被 json 序列化的数据类型有:str、int、bool、dict、list(tuple)、None,没有 setpickle 模块只支持 Python 语言的所有数据类型(包括对象)的网络传输

写入文件时可以写入多个shelve 模块也只支持 Python,一般与文件相关,即通过它把数据写入文件,拿出来后再反解成原数据类型

8. json 模块:安全模式的网络传输,一般项目中就使用它

######## 第一对方法:dumps loads ########

import json

# json 的序列化过程

dic = {"姓名": "张三", "爱好": ["喝酒", "玩游戏"]}

s = json.dumps(dic)

print(s, type(s))

# 运行结果:

{"\u59d3\u540d": "\u5f20\u4e09", "\u7231\u597d": ["\u559d\u9152", "\u73a9\u6e38\u620f"]}

# 使用 ensure_ascii=False 来显示中文

s = json.dumps(dic, ensure_ascii=False)

print(s, type(s))

# 运行结果:

{"姓名": "张三", "爱好": ["喝酒", "玩游戏"]}

# json 的反序列化过程

dic1 = json.loads(s)

print(dic1, type(dic1))

# 运行结果:

{'姓名': '张三', '爱好': ['喝酒', '玩游戏']}

# 注意:使用 print() 打印的字符串的内容,在终端都是显示单引号的

# 不管程序中字符串使用的是单引号还是双引号

# 而 json.dumps 用法对于字符串来说,都是双引号

######## 第二对:dump load(与文件相关)########

import json

dic = {"姓名": "张三", "爱好": ["喝酒", "玩游戏"]}

with open("test.json", mode="w", encoding="utf-8") as f1:

json.dump(dic, f1, ensure_ascii=False)

with open("test.json", encoding="utf-8") as f2:

ret = json.load(f2)

print(ret, type(ret))

# 运行结果:

# 首先,与本 py 文件同目录下多了一个 test.json 文件

{'姓名': '张三', '爱好': ['喝酒', '玩游戏']}

9. json 与 bytes 的区别bytes 只能操作 string,用于网络传输

json 可以操作几乎除了 set 之外的所有数据类型,不仅能用于网络传输,还能写入文件

10. 通过 json 模块将多个字典写入一个文件中

import json

dic1 = {"name": "Jane"}

dic2 = {"age": 18}

dic3 = {"hobby": "playing"}

with open("多个字典.json", encoding="utf-8", mode="w") as f1:

f1.write(json.dumps(dic1) + "\n")

f1.write(json.dumps(dic2) + "\n")

f1.write(json.dumps(dic3) + "\n")

with open("多个字典.json", encoding="utf-8") as f2:

for line in f2:

ret = json.loads(line)

print(ret, type(ret))

# 运行结果:

# 首先,与本 py 文件同目录下多了一个 多个字典.json 文件

{'name': 'Jane'}

{'age': 18}

{'hobby': 'playing'}

11. 一个坑

import json

dic = {1: "abc"}

ret = json.dumps(dic)

print(ret) # {"1": "abc"}

new_dic = json.loads(ret)

print(new_dic) # {'1': 'abc'}

# 发现键本来是数字 1,现在已经变成字符串形式的 1 了

# 也就是说并没有真正的还原过来

12. pickle 模块的基本用法

import pickle

dic = {"姓名": "张三", "爱好": ["喝酒", "玩游戏"]}

s = pickle.dumps(dic)

print(s)

# 运行结果:

b'\x80\x03}q\x00(X\x06\x00\x00\x00\xe5\xa7\x93\xe5\x90\x8dq\x01X\x06\x00\x00\x00\xe5\xbc\xa0\xe4\xb8\x89q\x02X\x06\x00\x00\x00\xe7\x88\xb1\xe5\xa5\xbdq\x03]q\x04(X\x06\x00\x00\x00\xe5\x96\x9d\xe9\x85\x92q\x05X\t\x00\x00\x00\xe7\x8e\xa9\xe6\xb8\xb8\xe6\x88\x8fq\x06eu.'

dic1 = pickle.loads(s)

print(dic1, type(dic1))

# 运行结果:

{'姓名': '张三', '爱好': ['喝酒', '玩游戏']}

13. 使用 pickle 模块将字典在文件中写入和写出

import pickle

dic = {"姓名": "张三", "爱好": ["喝酒", "玩游戏"]}

# 注意:这里的模式是 wb,而且不需要 encoding,否则会报错

with open("test.pickle", mode="wb") as f1:

pickle.dump(dic, f1)

with open("test.pickle", mode="rb") as f2:

ret = pickle.load(f2)

print(ret, type(ret))

# 运行结果:

# 首先,与本 py 文件同目录下生成了 test.pickle 文件

# 该文件里的内容:

8003 7d71 0028 5806 0000 00e5 a793 e590

8d71 0158 0600 0000 e5bc a0e4 b889 7102

5806 0000 00e7 88b1 e5a5 bd71 035d 7104

2858 0600 0000 e596 9de9 8592 7105 5809

0000 00e7 8ea9 e6b8 b8e6 888f 7106 6575

2e

# 然后是终端内的内容:

{'姓名': '张三', '爱好': ['喝酒', '玩游戏']}

14. 通过 pickle 模块将多个字典写入一个文件中(注意与 json 模块的区别)

import pickle

dic1 = {"name": "Jane"}

dic2 = {"age": 18}

dic3 = {"hobby": "playing"}

with open("test01.pickle", mode="wb") as f:

pickle.dump(dic1, f)

pickle.dump(dic2, f)

pickle.dump(dic3, f)

with open("test01.pickle", mode="rb") as f1:

ret1 = pickle.load(f1)

ret2 = pickle.load(f1)

ret3 = pickle.load(f1)

print(ret1, ret2, ret3)

# 运行结果:

# 首先,与本 py 文件同目录下生成了 test01.pickle 文件

# 该文件里的内容:

8003 7d71 0058 0400 0000 6e61 6d65 7101

5804 0000 004a 616e 6571 0273 2e80 037d

7100 5803 0000 0061 6765 7101 4b12 732e

8003 7d71 0058 0500 0000 686f 6262 7971

0158 0700 0000 706c 6179 696e 6771 0273

2e

# 然后是终端内的内容:

{'name': 'Jane'} {'age': 18} {'hobby': 'playing'}

15. 还可以将一个函数写入文件中

import pickle

def func():

print(666)

with open("test.pickle", mode="wb") as f:

pickle.dump(func, f)

with open("test.pickle", mode="rb") as f1:

ret = pickle.load(f1)

ret()

# 运行结果:

666

16. shelve 模块:也是 Python 提供给我们的序列化工具,比 pickle 用起来更简单一些。它只提供一个 open 方法,用 key 来访问,使用起来和字典类似

import shelve

f = shelve.open("shelve_file")

# 直接对文件句柄操作,就可以存入数据

f["key"] = {"int": 10, "float": 10.2, "string": "abc"}

f.close()

f1 = shelve.open("shelve_file")

ret = f1["key"]

f1.close()

print(ret)

# 运行结果:

# 首先生成了两个文件,一个是 shelve_file.bak,另一个是 shelve_file.dat

# 然后是终端内的内容:

{'int': 10, 'float': 10.2, 'string': 'abc'}

PS: 为了方便大家相互交流、解决学习过程中遇到的问题,我新建了一个 QQ 群,感兴趣的小伙伴加进来一起学习吧!~ (群号码:697678250,加群请备注:笔记)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值