今日主要内容
- 内置模块(标准库)
- 序列化
- hashlib
- collections
- 软件开发规范
一、内置模块(标准库)
(一)序列化模块
- 什么是序列化?
- 将一种数据结构(如列表、字典)转换为另一种特殊的数据结构(如字符串、bytes类型)的过程就是序列化过程
- 数据传输的过程中,传输的都是字节,现在有一个列表需要传输,我需要将列表转换为字符串,在将字符串进行编码,但对方最终接收到的是一个字符串,字符串是不能原封不动的还原成列表的,这时候就需要用到反序列化将字符串转换回列表
1.json模块(重要)
json文件相当于编程界的普通话,是各种语言交互的枢纽,当数据需要在多种语言间传输,就必须将数据转换成json字符串,对方将接受到的json字符串再转换成对应语言的数据类型,完美还原
json模块方法介绍:
json.dumps() 将对象序列化 json.loads() 将对象反序列化 json.dump() 将对象序列化写入文件 json.load() 将对象读取后反序列化 dumps、loads
:用于网络传输dump、load
:用于文件写读
json.dumps()
- 函数定义:
dumps(obj, *, skipkeys=False, ensure_ascii=True, check_circular=True, allow_nan=True, cls=None, indent=None, separators=None, default=None, sort_keys=False, **kw)
- 函数说明:将对象序列化为json格式的字符串,其余参数中的
ensure_ascii
:若对象中出现的非ascii字符(如中文)时会被转换,若显示原字符,指定ensure_ascii=False
import json print(json.dumps(["张旭东666"])) print(json.dumps(["张旭东666"], ensure_ascii=False)) 运行结果: ["\u5f20\u65ed\u4e1c666"] ["张旭东666"]
- 函数定义:
json.loads()
- 函数定义:
loads(s, *, encoding=None, cls=None, object_hook=None, parse_float=None, parse_int=None, parse_constant=None, object_pairs_hook=None, **kw)
- 函数说明:将json格式的字符串反序列化
import json print(json.loads("[1,2,3,4]")) print(type(json.loads("[1,2,3,4]"))) 运行结果: [1, 2, 3, 4]
- 函数定义:
json.dump()
- 函数定义:
dump(obj, fp, *, skipkeys=False, ensure_ascii=True, check_circular=True, allow_nan=True, cls=None, indent=None, separators=None, default=None, sort_keys=False, **kw)
- 函数说明:将对象转换为json流写入到文件(fp为文件句柄)中
import json with open("text.txt", "w", encoding="utf-8") as f: json.dump([1, 2, 3, 4], f)
- 函数定义:
json.load()
- 函数定义:
load(fp, *, cls=None, object_hook=None, parse_float=None, parse_int=None, parse_constant=None, object_pairs_hook=None, **kw)
- 函数说明:读取文件句柄并将字符串反序列化
with open("text.txt", encoding="utf-8") as f: lst = json.load(f) print(lst) print(type(lst)) 运行结果: [1, 2, 3, 4]
- 函数定义:
如果向文件中写入多个json串,无法读取,因为在文件中写入的都是一行内容
- 解决方法1:将所有内容准备好了一次性写入和读取
import json lst = [{"k1": 1}, {"k2": 2}, {"k3": 3}] # 准备好放在一起 with open("text.txt", "w+", encoding="utf-8") as f: json.dump(lst, f) # 一起写入 f.seek(0) for el in json.load(f): # 一起读取 print(el) 运行结果: {'k1': 1} {'k2': 2} {'k3': 3}
- 解决方法2:改用
dumps
和loads
对每一行分别进行处理
import json lst = [{"k1": 1}, {"k2": 2}, {"k3": 3}] with open("text.txt", "w+", encoding="utf-8") as f: for el in lst: f.write(json.dumps(el)+"\n") # 利用write和dumps一行一行序列化写入 f.seek(0) for line in f: print(json.loads(line)) # 一行一行读取反序列化 运行结果: {'k1': 1} {'k2': 2} {'k3': 3}
2.pickle模块
pickle模块将所有数据类型和对象序列化转换成bytes类型(不支持lambda匿名函数),还可以反序列化还原回原数据,pickle模块只能在python语言中使用,其他语言不识别
pickle模块支持多行序列化写入和多行读取反序列化功能
pickle模块方法介绍:
pickle.dumps() 将对象序列化 pickle.loads() 将对象反序列化 pickle.dump() 将对象序列化写入文件 pickle.load() 将对象读取后反序列化 dumps、loads
:用于网络传输dump、load
:用于文件写读- pickle的方法和json完全相同,与json的区别就是pickle序列化后是字节,而json序列化后是字符串
3.shelve模块(了解)
- 了解一下就好,这里不做介绍
(二)hashlib模块
hashlib模块被人称为加密算法、摘要算法等,它的功能是用来对数据进行加密和文件校验使用,通过模块中的功能函数将数据转换为一个固定长度的字符串
数据转换流程:
- 明文 —— 字节 —— 密文
hashlib模块的特点:
- 转换的密文没有规律
- 操作不可逆
- 不同的bytes类型数据转换的密文一定不同
import hashlib sha1 = hashlib.sha1() sha1.update("21".encode("utf-8")) # 将21转换为密文 print(sha1.hexdigest()) sha1 = hashlib.sha1() sha1.update("12".encode("utf-8")) # 将12转换为密文 print(sha1.hexdigest()) 运行结果: # 结果一定不同,且无规律 472b07b9fcf2c2451e8781e944bf5f77cd8457c8 7b52009b64fd0a2a49e6d8a939753077792b0554
- 相同的bytes类型数据转换的密文一定相同
import hashlib sha1 = hashlib.sha1() sha1.update("12".encode("gbk")) # 用gbk进行编码 print(sha1.hexdigest()) sha1 = hashlib.sha1() sha1.update("12".encode("utf-8")) # 用utf-8进行编码 print(sha1.hexdigest()) 运行结果: # 内容相同,无论编码方式是什么,密文一定相同, 7b52009b64fd0a2a49e6d8a939753077792b0554 7b52009b64fd0a2a49e6d8a939753077792b0554
加密方式:
- md5
- sha1
- sha256
- sha512
模块应用一:对数据进行加密
方法介绍:
hashlib.md5() 对应加密方式初始化 obj.update() 向初始化的对象中添加要加密的内容,内容必须是字节码 obj.hexdigest() 对对象进行加密 普通加密:
import hashlib md5 = hashlib.md5() # 初始化使用md5加密方式的对象 md5.update("zxd666".encode("utf-8")) # 向对象添加要加密的内容,内容必须为字节码 print(md5.hexdigest()) # 进行加密 运行结果: fe02a10cda698ceb5a03022189199c49 # 相同明文,密文一定相同
加盐加密:
- 固定加盐:
import hashlib md5 = hashlib.md5("盐".encode("utf-8")) # 在初始化时可以对要加密的明文进行固定加盐,盐也需要转换为字节码 md5.update("zxd666".encode("utf-8")) print(md5.hexdigest()) 运行结果: 2bc9ae4e838be80068a6e4963626b92c # 相同明文,密文一定相同
- 动态加盐:
import hashlib user = input("账号:") pwd = input("密码:") md5 = hashlib.md5(user.encode("utf-8")) # 利用账号来给密码加盐,每个人的账号都不同,起到了动态加盐的效果 md5.update(pwd.encode("utf-8")) print(md5.hexdigest()) 运行结果: 账号:zxd 密码:zxd123 ddca7a4709d99ac8d1b3012b2e6a364a
obj.update()
方法可以多次添加需要加密的内容import hashlib md5 = hashlib.md5() md5.update("zxd".encode("utf-8")) md5.update("666".encode("utf-8")) # 可以分开多次添加 print(md5.hexdigest()) 运行结果: fe02a10cda698ceb5a03022189199c49 # 与上面例子中普通加密的密文相同
模块应用二:用于文件一致性校验
- linux讲究:一切皆文件,我们普通的文件,视频,音频,图片,以及应用程序等都是文件。我们都从网上下载过资源,比如我们下载的Python解释器,当时你可能没有注意过,其实你下载的时候都是带一个MD5或者shax值的,为什么? 我们的网络世界是很不安全的,经常会遇到病毒,木马等,有些你是看不到的可能就植入了你的电脑中,那么他们是怎么来的? 都是通过网络传入来的,就是你在网上下载一些资源的时候,趁虚而入,当然大部分被我们的浏览器或者杀毒软件拦截了,但是还有一部分偷偷的进入你的磁盘中了。那么我们自己如何验证我们下载的资源是否有病毒呢?这就需要文件的一致性校验了。在我们下载一个软件时,往往都带有一个MD5或者shax值,当我们下载完成这个应用程序时你要是对比大小根本看不出什么问题,你应该对比他们的md5值,如果两个md5值相同,就证明这个应用程序是安全的,如果你下载的这个文件的MD5值与服务端给你提供的不同,那么就证明你这个应用程序肯定是植入病毒了(文件损坏的几率很低),那么你就应该赶紧删除,不应该安装此应用程序。
- 我们之前说过,md5计算的就是bytes类型的数据的转换值,同一个bytes数据用同样的加密方式转化成的结果一定相同,如果不同的bytes数据(即使一个数据只是删除了一个空格)那么用同样的加密方式转化成的结果一定是不同的。所以,hashlib也是验证文件一致性的重要工具。
文件校验实例:
import hashlib def file_check(file_path): with open(file_path,mode='rb') as f1: sha256 = hashlib.md5() while 1: content = f1.read(1024) if content: sha256.update(content) else: return sha256.hexdigest() print(file_check('python-3.6.8-amd64.exe'))
(三)collections模块
- collections模块提供了一些额外的数据类型和一些集合类的操作
之前提到过的官方判断可迭代对象和迭代器的方法:Iterable、Iterator
from collections import Iterable, Iterator lst = [1,2,3,4,5] l_iter = iter(lst) print(isinstance(lst, Iterable)) print(isinstance(l_iter, Iterator)) 运行结果: True True
Counter类(统计)
- Counter类是一个计数器,可以用来统计每个元素出现的次数,返回的是一个Counter对象
from collections import Counter lst = [1, 2, 6, 2, 4, 4, 6, 2, 4, 5, 4, 4, 2, 3, 2, 1] print(dict(Counter(lst))) 运行结果: {1: 2, 2: 5, 6: 2, 4: 5, 5: 1, 3: 1}
- Counter还可以用来去重
from collections import Counter lst = [1, 2, 6, 2, 4, 4, 6, 2, 4, 5, 4, 4, 2, 3, 2, 1] print(list(Counter(lst))) 运行结果: [1, 2, 6, 4, 5, 3]
deque类(双向队列)
- deque类是一个双向队列,在双向队列之前先了解一下 栈 和 队列 的定义
- 栈:FILO 先进后出(比如上下电梯轿厢)
- 队列:FIFO 先进先出(所有的排队)
- 利用deque类来建立双向队列,以及操作双向队列
from collections import deque q = deque() q.append(3) q.append(4) q.appendleft(2) q.appendleft(1) print(list(q)) print(q.pop()) print(q.popleft()) print(list(q)) 运行结果: [1, 2, 3, 4] 4 1 [2, 3]
- deque类是一个双向队列,在双向队列之前先了解一下 栈 和 队列 的定义
OrderedDict类(有序字典)
- 顾名思义,通过OrderedDict类创建的字典是有序的
from collections import OrderedDict dic = {"k1": 1, "k2": 2, "k3": 3} print(dic) od = OrderedDict({"k1": 1, "k2": 2, "k3": 3}) print(od) print(od["k1"]) 运行结果: {'k1': 1, 'k2': 2, 'k3': 3} OrderedDict([('k1', 1), ('k2', 2), ('k3', 3)]) # 位置固定 1 # 可以像正常字典取值
defaultdict类(默认字典)
- 通过defaultdict类创建的字典可以给字典设置默认值,当key不存在时,直接获取默认值
from collections import defaultdict df = defaultdicr(list) print(df["k1"]) 运行结果: []
namedtuple类(命名元组)
- 通过namedtuple类创建元组可以给元组内的元素命名
from collections import namedtuple nt = namedtuple("num", ["x", "y"]) # 定义元组名、元素名(其实这里是创建了一个类) p = nt(1, 2) print(p) print(p.x) print(p.y) 运行结果: num(x=1, y=2) 1 2
二、软件开发规范
软件开发规范:分文件管理,增强耦合性
-
bin 启动文件目录 lib 公共组件目录 core 主逻辑目录 db 相关数据目录 log 日志 conf 配置文件目录