序列化模块
什么是序列化,就是将原本的字典、列表等内容转换成json字符串的过程就叫 序列化。
什么是反序列化,就是将json字符串转为其他数据类型的过程就是 反序列化。
为何要有序列化模块
比如,我们在python代码中计算的一个数据需要给另外一段程序使用,那我们怎么给?
现在我们能想到的方法就是存在文件里,然后另一个python程序再从文件里读出来。
但是我们都知道,对于文件来说是没有字典这个概念的,所以我们只能将数据转换成字典放到文件中。
你一定会问,将字典转换成一个字符串很简单,就是str(dic)就可以办到了,为什么我们还要学习序列化模块呢?
没错序列化的过程就是从dic 变成str(dic)的过程。现在你可以通过str(dic),将一个名为dic的字典转换成一个字符串,
但是你要怎么把一个字符串转换成字典呢?
聪明的你肯定想到了eval(),如果我们将一个字符串类型的字典str_dic传给eval,就会得到一个返回的字典类型了。
eval()函数十分强大,但是eval是做什么的?e官方demo解释为:将字符串str当成有效的表达式来求值并返回计算结果。
BUT!强大的函数有代价。安全性是其最大的缺点。
想象一下,如果我们从文件中读出的不是一个数据结构,而是一句"删除文件"类似的破坏性语句,那么后果实在不堪设设想。
而使用eval就要担这个风险。
所以,我们并不推荐用eval方法来进行反序列化操作(将str转换成python中的数据结构)
json模块为我们提供了四个功能:dumps、dump、loads、load
loads和dumps
import json
dic = {'k1':'v1','k2':'v2','k3':'v3'}
str_dic = json.dumps(dic) #序列化:将一个字典转换成一个字符串
print(type(str_dic),str_dic) #<class 'str'> {"k3": "v3", "k1": "v1", "k2": "v2"}
#注意,json转换完的字符串类型的字典中的字符串是由""表示的
dic2 = json.loads(str_dic) #反序列化:将一个字符串格式的字典转换成一个字典
#注意,要用json的loads功能处理的字符串类型的字典中的字符串必须由""表示
print(type(dic2),dic2) #<class 'dict'> {'k1': 'v1', 'k2': 'v2', 'k3': 'v3'}
list_dic = [1,['a','b','c'],3,{'k1':'v1','k2':'v2'}]
str_dic = json.dumps(list_dic) #也可以处理嵌套的数据类型
print(type(str_dic),str_dic) #<class 'str'> [1, ["a", "b", "c"], 3, {"k1": "v1", "k2": "v2"}]
list_dic2 = json.loads(str_dic)
print(type(list_dic2),list_dic2) #<class 'list'> [1, ['a', 'b', 'c'], 3, {'k1': 'v1', 'k2': 'v2'}]
load和dump
import json
f = open('json_file','w')
dic = {'k1':'v1','k2':'v2','k3':'v3'}
json.dump(dic,f) #dump方法接收一个文件句柄,直接将字典转换成json字符串写入文件
f.close()
f = open('json_file')
dic2 = json.load(f) #load方法接收一个文件句柄,直接将文件中的json字符串转换成数据结构返回
f.close()
print(type(dic2),dic2)
pickle
pickle模块提供了四个功能:dumps、dump(序列化,存)、loads(反序列化,读)、load (不仅可以序列化字典,列表...可以把python中任意的数据类型序列化)
import pickle
dic = {'k1':'v1','k2':'v2','k3':'v3'}
str_dic = pickle.dumps(dic)
print(str_dic) #一串二进制内容
dic2 = pickle.loads(str_dic)
print(dic2) #字典
import time
struct_time = time.localtime(1000000000)
print(struct_time)
f = open('pickle_file','wb')
pickle.dump(struct_time,f)
f.close()
f = open('pickle_file','rb')
struct_time2 = pickle.load(f)
print(struct_time2.tm_year)
hashlib模块
Python的hashlib提供了常见的摘要算法,如MD5,SHA1等等。
什么是摘要算法呢?摘要算法又称哈希算法、散列算法。它通过一个函数,把任意长度的数据转换为一个长度固定的数据串(通常用16进制的字符串表示)。
摘要算法就是通过摘要函数f()对任意长度的数据data计算出固定长度的摘要digest,目的是为了发现原始数据是否被人篡改过。
摘要算法之所以能指出数据是否被篡改过,就是因为摘要函数是一个单向函数,计算f(data)很容易,但通过digest反推data却非常困难。而且,对原始数据做一个bit的修改,都会导致计算出的摘要完全不同。
我们以常见的摘要算法MD5为例,计算出一个字符串的MD5值:
import hashlib
md5 = hashlib.md5()
md5.update('how to use md5 in python hashlib?')
print md5.hexdigest()
计算结果如下:
d26a53750bc40b38b65a520292f69306
如果想要密码加密更复杂就需要‘加盐’
#### 加盐:加密的时候在多一个干扰项
## 注册功能
# username = input('username:>>>').strip()
# password = input('password:>>>').strip()
#
# s_passowrd = password + 'qaz'
# m = hashlib.md5()
# m.update(s_passowrd.encode('utf-8'))
# new_pwd = m.hexdigest()[0:16]
# data = '%s|%s' % (username, new_pwd)
#
# with open('userinfo.txt', 'w', encoding='utf-8') as f:
# f.write(data)
还有一个就是动态加盐
#写一个密码加密登录验证功能
import hashlib,random
#先写一个随机验证码
def code():
code=''
for i in range(4):
rand_int=str(random.randint(0,9))
rand_upper=chr(random.randint(65,90))
rand_lower=chr(random.randint(97,122))
rand_code=random.choice([rand_lower,rand_upper,rand_int])
code+=rand_code
return code
random_str=code()
#注册功能
def register():
inp_username=input('输入用户名:')
inp_pwd=input('输入密码:')
s_pwd=inp_pwd+random_str#给密码加上随机字符串
md5=hashlib.md5()
md5.update(s_pwd.encode('utf-8'))
new_psd=md5.hexdigest()#用md5进行密码加密
info='%s|%s|%s' %(inp_username,new_psd,random_str)#为了提取密码进行比对更方便
with open('a.txt','w',encoding='utf-8') as f:
f.write(info)
register()
#登录功能
def login():
user_name=input('请输入用户名:')
user_pwd=input('请输入密码:')
s_pwd = user_pwd + random_str
md5=hashlib.md5()
md5.update(s_pwd.encode('utf-8'))
new_user_pwd=md5.hexdigest()
with open('a.txt','r',encoding='utf-8') as f:
data_username, data_password, data_code = f.readline().split('|')
if user_name==data_username and new_user_pwd==data_password:
print('登录成功')
else:
print('用户名和密码不正确')
return login
login()