面向对象进阶------>模块 json pickle hashlib
何为模块呢? 其实模块就是.py文件
python之所以好用就是模块多
模块分三种 : 内置模块 、 拓展模块、自定义模块、
现在我们来认识:内置模块中的 序列化模块和 hashlib 模块
1、什么是序列化:将原本的字典 列表等字类的形式转化成字符串的过程就是序列化
2、为什么序列化:
1:以某种存储的形式使自定义对象持久化 #就好比你定义的字典的类型的内容 它可能人输入完就结束了 没有了 我们可以把它转化为字符串类型的 进行存储在文件中或者数据库中
2:将对象从一个地方传递到另一个地方 #网络之间的信号传输你需要进行电信号传输 然后你要把你的传输内容转化为字符串类型的才可以进行传输
3:使程序更具维护性
使用模块就需要把这些定义好的模块导入你的程序内才能使用它的功能 所以就必须使用import进行导入
实例化是创造一个实例,序列化就是创造一个序列的
eg:dic ----->str 这就是序列化的过程
python中的序列化模块:
json:所有的编程语言都通用的序列化格式,也就是你可以把你的内容传递给java 之类的语言 它也是支持的
缺点:它支持的数据类型非常有限,仅仅支持 数字 字符串 列表 字典
pickle:只能在python语言中的程序之间传递数据用
优点;pickle 支持python中的所有的数据类型的使用
shelve :python3X之后才有的
使用序列化模块把内容进行转化的时候把内容存储起来的一定是字符串类型的或者字节
但是进行网络传输一定是字节
对序列化进行操作的需要有四个功能;
dumps ------->把你的内容进行序列化
loads ------>把你的内容进行反序列化
上面两个是直接对内容进行操作 下面是对文件的进行操作
dump -----> 把你要存进文件 内的内容进行序列化
load--------> 把你文件内的内容进行反序列化
json和pickle的读取文件是不同的 因为json读取文件是只能一行存储一个字典的 所以一次只能读取一个
也就是带s的只能对内存中的数据信息操作 不带s的对文件内的存储信息进行操作
只在内存中操作数据 主要用于网络传输 和多个数据与文件打交道
首先你要使用序列化模块你要导入模块
json 内的dumps 和 loads :
import json #导入json模块 dic ={'桑塔纳':(190,80)} print(dic) #看看你所打印出来的信息 {'桑塔纳': (190, 80)} print(type(dic)) #查看你的字典的具体信息是什么 <class 'dict'> ret = json.dumps(dic) #把你的字典进行序列化 转化为字符串 print(ret) #得到 {"\u6851\u5854\u7eb3": [190, 80]} 里面的内容变成两个引号的了 print(type(ret)) #看看你转化后的信息就是字符串类型了 <class 'str'> # 上面是序列化下面是反序列化 就是你存储后想把这些信息提取出来 查看 或者你传递的信息想要查看 都要进行序列化 res = json.loads(ret) #把你序列化后的ret进行反序列化 print(res) #得到{'桑塔纳': [190, 80]} print(type(res)) #这个时候你看又回到了dic的类型 进行反序列化后又回到了最初的类型
从上面的显示中可以看出你序列化后的所有的内容都会以双引号的形式显示出来
json内的dump和load
with open('序列化','w', encoding = 'UTF-8')as f : #因为json只能一次读取一个写入的字典 所以你写入的时候也要一次写入一个 json.dump(dic,f,ensure_ascii=False) #这是标准语句后面必须加上 ensure_ascii = False with open ('序列化', encoding ="UTF-8")as f : ret = json.load(f) #反序列化 print(ret) f = open('序列化', 'w', encoding = 'UTF-8') json.dump(dic,f,ensure_ascii=False) f.close() f = open('序列化',encoding ='UTF-8') ret = json.load(f) print(ret) f.close()
你在写入文件的时候不加sure_ascii = False 存进去的就会是乱码的状态 但是你读取出来还是正常的
当你写入多个文件的时候必须要用dump和load 因为你从文件中读取的时候load只能读取一行一行的 所以你存入的时候也要想办法存储的收分行就需要在存入之前进行序列化
你要进行多个序列化然后存储到文件内 必须要转化使用dumps和loads:
import json dic1= {'老大':(123)} dic2 = {'老二':(345)} dic3 ={'老三':(678)} f = open('大表哥', 'w', encoding = 'UTF-8') ret1 = json.dumps(dic1,f,ensure_ascii =False) f.write(ret1+'\n') ret2 = json.dumps(dic2,f) f.write(ret2+'\n') #不加ensure_ascii = False显示的就是会乱码但是你读取出来不会的 所以你可以选择写或者不写 ensure_ascii = False ret3 = json.dumps(dic3) f.write(ret3+'\n') f.close() f = open('大表哥', encoding = 'UTF-8') # ret = json.load(f) #这样写实惠报错的 因为load不能多行读取只能一行一行读取 for line in f : print(json.loads(line.strip())) #因为你的load只能一行一行读取 f.close()
反序列化必须和序列化一起使用 反序列化不能单独使用 json
json如果是对字典序列化的话 这个字典的key必须事str的不能事其他类型
dic = {"190, 90,'捏脚'":'大表哥'} #json 不支持元组 不支持除了str类型以外的key print(json.dumps(dic)) 这就是错的
json除了能对字典操作外 还可以对列表元组操作
dic =['999','www'] print(json.dumps(dic)) #结果["999", "www"] ty = (1111) print(json.dumps(ty)) #结果1111
pickle模块:
dumps 和 loads
它的序列化模块不是一个可读的字符串而是一个bytes类型 就是pickle.dumps得到的内容就是bytes类型
其实pickle.dumps loads和json的都差不多只不过pickle的存储是以字节的形式存储的
import pickle dic = {(190,90,'捏脚'):'大表哥'} ret = pickle.dumps(dic) print(ret) # 结果b'\x80\x03}q\x00K\xbeKZX\x06\x00\x00\x00\xe6\x8d\x8f\xe8\x84\x9aq\x01\x87q\x02X\t\x00\x00\x00\xe5\xa4\xa7\xe8\xa1\xa8\xe5\x93\xa5q\x03s.' print(pickle.loads(ret))
dump和 load
f = open('序列化','wb') pickle.dump(dic,f) f.close() f = open('序列化', 'rb') print(pickle.load(f)) f.close() # 不论是读还是写 都要以+b的形式来进行因为 pickle就是对字节进行操作的
pickle模块多写的:
import pickle dic1 = {'大表哥':(190,70)} dic2 ={(222):333} dic3 = {(123):'nishou'} f = open('大表哥3', 'wb') pickle.dump(dic1,f) pickle.dump(dic2,f) pickle.dump(dic3,f) f.close() f = open('大表哥3', 'rb') #必须以b的形式来读取 while True : try: print(pickle.load(f)) except EOFError: break
json模块和pickle模块两者多行写入的时候对比:
json模块在写入多次dump的时候,不能对应执行多次 load来取出数据,而pickle模块可以一次去除多个数据
json如果要写入多个元素可以先将元素 dumps序列化 ,f.write(序列化, +'\n') 来写入文件
读取文件的时候应该按照逐行读取 再使用loads来把读出来的字符串转化为对应的数据类型
关于序列化自定义类的对象:
class A: def __init__(self,name,age): self.name = name self.age = age a = A('egon', 15) import json # json.dumps(a) #报错 不可以对对象进行序列化 import pickle ret = pickle.dumps(a) print(ret) obj = pickle.loads(ret) print(obj.__dict__) import pickle # f = open('大侄子1', 'wb') # pickle.dump(a,f) # f.close() f = open('大侄子1', 'rb') # print(pickle.load(f)) obj =pickle.load(f) print(obj.__dict__) #因为打的是对象只能打的是对象的地址 f.close()
序列化 把数据类型变成字符串
为什么要有序列化 因为在网络上和文件中能存在的只有字节
json 在所有语言中通用 只对有限的数据类型进行序列化 字典 列表 字符串 数字 元组
在多次写入dump数据进入文件的时候,不能通过load来取。
pickle 只能在python中使用 对绝大多数数据类型都可以进行序列化
在load的时候,必须拥有被load数据类型对应的类在内存里
dumps 序列化
loads 反序列化
dump 直接向文件中序列化
load 直接对文件反序列化
shevlve 模块:
是python专有的序列化模块 只针对文件
import shelve # python 专有的序列化模块 只针对文件 f = shelve.open('shelve_file') # 打开文件 f['key'] = {'int':10, 'float':9.5, 'string':'Sample data'} #直接对文件句柄操作,就可以存入数据 f.close() import shelve f1 = shelve.open('shelve_file') existing = f1['key'] #取出数据的时候也只需要直接用key获取即可,但是如果key不存在会报错 f1.close() print(existing) 设置只读方式 import shelve f = shelve.open('shelve_file', flag='r') existing = f['key'] f.close() print(existing) import shelve f = shelve.open('shelve_file', flag='r') # f['key']['int'] = 50 # 不能修改已有结构中的值 # f['key']['new'] = 'new' # 不能在已有的结构中添加新的项 f['key'] = 'new' # 但是可以覆盖原来的结构 f.close() # import shelve f1 = shelve.open('shelve_file') existing = f1['key'] #取出数据的时候也只需要直接用key获取即可,但是如果key不存在会报错 f1.close() print(existing) import shelve f1 = shelve.open('shelve_file') print(f1['key']) f1['key']['new_value'] = 'this was not here before' f1.close() import shelve f1 = shelve.open('shelve_file') existing = f1['key'] #取出数据的时候也只需要直接用key获取即可,但是如果key不存在会报错 f1.close() print(existing) import shelve f2 = shelve.open('shelve_file', writeback=True) print(f2['key']) f2['key']['new_value'] = 'this was not here before' f2.close() f1 = shelve.open('shelve_file') existing = f1['key'] #取出数据的时候也只需要直接用key获取即可,但是如果key不存在会报错 f1.close() print(existing)
hash 哈希算法 可hash数据类型——>数字的过程
hashlib模块:
hashlib 摘要算法
过程不可逆,并且在不同的时刻对同一个字符串进行加密得到的结果相同:
也是一些算法的集合,有好多算法
字符串 --> 数字
不同的字符串 --> 数字一定不同
无论在哪台机器上,在什么时候计算,对相同的字符串结果总是一样的
摘要过程不可逆
先定义一个变量来等于hashlib.md5() 就是创造一个hashlib.md5()的对象 然后对这个对象传参进行一些操作
然后再用你接受的变量.update('加密内容'.encode('UTF-8'))
然后把你的加密内容给打印出来用hexdigest prit(变量.hexdigest())
eg:
你要对你好这两个字加密
先声明你要加密的是哪种方式
import hashlib
m = hashlib.md5()
m.update('nihao'.encode('UTF-8')) 这个encdoe(‘UTF-8’)可以省略不写 不写的话前面的必须是字节类型的加个b
print(m.hexdigest())
hash = hashlib.md5()#md5对象,md5不能反解,但是加密是固定的,就是关系是一一对应,所以有缺陷,可以被对撞出来 hash.update(bytes('admin',encoding='utf-8'))#要对哪个字符串进行加密,就放这里 print(hash.hexdigest())#拿到加密字符串
hashlib进行加密的时候也可以使用字节的形式进行加盐
import hashlib m =hashlib.md5('alex'.encode('utf-8')) m.update('sb'.encode('UTF-8')) print(m.hexdigest()) # m = hashlib.md5(b'bilibili') # m.update('12345'.encode('utf-8')) user = b'bilibili' m = hashlib.md5(user[::-1]) m.update('12345'.encode('utf-8')) print(m.hexdigest()) user = b'bilibili' m = hashlib.md5(user[::-1]) m.update('12345'.encode('utf-8')) print(m.hexdigest()) # 387ffb1c9f5bbd7ad86ab3a7a44115bf
我们这种加太单一容易被破解 我们可以分开加密 又叫加盐
加盐就是在第一行就对你要加密的文件进行加密 然后下面再加密一部分
import hashlib m = hashlib.md5('alex'.encode('UTF-8')) #这个是盐 也就是要对下面的加密的部分再添加一个加密部分 m.update('issb'.encode('UTF-8')) print(m.hexdigest())
对issb加密的时候再加一个alex的盐
动态加盐:
如果还怕被破解可以根据动态加密然后根据它的下标什么的加密
import hashlib n = 'alexnnnn' m = hashlib.md5(n[0:3:-1].encode('UTF-8')) m.update('issb'.encode('UTF-8')) print(m.hexdigest())
无论是加盐还是动态加盐 得到的都是他们的和
并且加盐和不加盐那么你进行加盐的字符串和不加盐的字符串一样得到的密文不一样:
import hashlib s = 'nishiyigedameinv' m = hashlib.md5(s[::2].encode('UTF-8')) m.update('alex'.encode('UTF-8')) print(m.hexdigest()) # 9结果:c35f17fb25932c767dca4990f64dd0a s = 'nishiyigedameinvalex' m = hashlib.md5() m.update(s[::2].encode('UTF-8')) print(m.hexdigest()) # 结果:fcd2ac4087c68c0dda62ec8a4e0bcbd4
一段字符串直接进行加密和分开进行加密得到的结果是相同的:
import hashlib md5obj = hashlib.md5() md5obj.update(b'laowang') md5obj.update(b'your') md5obj.update(b'wife') md5obj.update(b'in') md5obj.update(b'myquilt') print(md5obj.hexdigest()) # 结果def757b8fec986c7438e72fe55a1f090 s = 'laowangyourwifeinmyquilt' md5obj = hashlib.md5() md5obj.update(s.encode('UTF-8')) print(md5obj.hexdigest()) # 结果ef757b8fec986c7438e72fe55a1f090
写一个函数来确定你的两个数值一样不
import hashlib def func(filename): m = hashlib.md5() m.update(filename.encode('UTF-8')) return m.hexdigest() a = 'laowang' b = 'laowang' # print(func(a))# b1132aa640bd78495f38f611d7cc0d19 # print(func(b)) # b1132aa640bd78495f38f611d7cc0d19 if func(a) == func(b): print(True) else: print('False')
经典代码:
import hashlib # md5算法 通用的算法 # sha算法 安全系数更高,sha算法有很多种,后面的数字越大安全系数越高, # 得到的数字结果越长,计算的时间越长 m = hashlib.md5() m.update('alex3714'.encode('utf-8')) print(m.hexdigest()) m = hashlib.md5() m.update('dazhizi sha'.encode('utf-8')) print(m.hexdigest()) m = hashlib.md5() m.update('123456'.encode('utf-8')) print(m.hexdigest()) # 将所有常见的密码 md5摘要 # 密码 摘要结果 # 暴力破解 和 撞库 # 加盐 m = hashlib.md5('wahaha'.encode('utf-8')) m.update('123456'.encode('utf-8')) print(m.hexdigest()) # d1c59b7f2928f9b1d63898133294ad2c # 123456 m = hashlib.md5('wahaha'.encode('utf-8')) m.update('123456'.encode('utf-8')) print(m.hexdigest()) # 动态加盐 # 500 用户名 和 密码 # 123456 # 111111 d1c59b7f2928f9b1d63898133294ad2c # pwd username username = 'alex' m = hashlib.md5(username[:2:2].encode('utf-8')) m.update('123456'.encode('utf-8')) print(m.hexdigest()) # d1c59b7f2928f9b1d63898133294ad2c # 文件的一致性校验 周一讲
还有一个sha模块 也是加密 一般都是sha1加密和md5加密一样的使用 这个更加不难被破解
不同的加密方法得到的密文不一样 ,但是一般都用md5 因为它速度快
import hashlib m = hashlib.sha1() m.update(b'12345') m.update('12345'.encode('UTF-8')) print(m.hexdigest())