今日主要内容
1.python内置模块-序列化模块
python中的序列化模块
json 所有的编程语言都通用的序列化格式....它支持的数据类型非常有限 数字 字符串 列表 字典
pickle 只能在python语言的程序之间传递数据用的..pickle支持python中所有的数据类型
shelve python3.* 之后才有的
2.摘要模块---hashlib
3.一道经典面试题
第一.python内置模块---序列化
***所有的导入模块都需要把import放在文件首位
什么叫序列化
能存储在文件中的一定是字符串 或者是 字节
能在网络上传输的 只有字节
所以为了能够对我们需要的数据进行存储或者传输就需要对数据进行序列化
以前是怎样序列化的呢?
dic = {"大表哥":(190,90)}
dic --> 字符串 # 序列化
字符串 --> dic # 反序列化
由此可知:
序列化 等于创造一个序列,就是创造一个字符串
实例化 等于创建一个实例
如何使用json
#讲解标准序列化的操作
1.json
import json
例:dumps和loads
#序列化
import json dic = {'小样':(190,90,'捏脚')} ret = json.dumps(dic) ret1 = json.dumps(dic,ensure_ascii=False) print(ret) print(ret1)
#反序列化
import json dic = {'小样':(190,90,'捏脚')} ret = json.dumps(dic) ret1 = json.dumps(dic,ensure_ascii=False) res = json.loads(ret) res1 = json.loads(ret1) print(type(res),res) #返回传入数据格式
例:dump和load 是直接将对象序列化之后写入文件,依赖一个文件句柄
dic = {'小样':(190,90,'捏脚')} #序列化 f = open('小样','w',encoding='utf-8') json.dump(dic,f) f.close() 结果:(文件内容) {"\u5c0f\u6837": [190, 90, "\u634f\u811a"]}
增加一个标准输出的参数:
import json dic = {'小样':(190,90,'捏脚')} f = open('小样','w',encoding='utf-8') json.dump(dic,f,ensure_ascii=False) f.close() 结果: {"小样": [190, 90, "捏脚"]}
反序列化输出
import json dic = {'小样':(190,90,'捏脚')} f = open('小样',encoding='utf-8') wt = json.load(f) f.close() print(wt) 结果: (原型输出) {'小样': [190, 90, '捏脚']}
如何应付多个字典序列化?
例:
import json dic1 = {"大表哥":(190,90,'捏脚')} dic2 = {"2表哥":(190,90,'捏脚')} dic3 = {"3表哥":(190,90,'捏脚')} f = open('大表哥','a',encoding='utf-8') str1 = json.dumps(dic1) #分别进行序列化,并序列化后进行手动换行 f.write(str1+'\n') str2 = json.dumps(dic2) f.write(str2+'\n') str3 = json.dumps(dic3) f.write(str3+'\n') f.close() 结果: '大表哥'文件内容 {"\u5927\u8868\u54e5": [190, 90, "\u634f\u811a"]} {"2\u8868\u54e5": [190, 90, "\u634f\u811a"]} {"3\u8868\u54e5": [190, 90, "\u634f\u811a"]}
多字典的反序列化
f = open('大表哥','r',encoding='utf-8') for line in f: print(json.loads(line.strip())) f.close() #结果 #利用循环对文件进行分别读取,然后json.loads进行反序列化 {'大表哥': [190, 90, '捏脚']} {'2表哥': [190, 90, '捏脚']} {'3表哥': [190, 90, '捏脚']}
dumps序列化 loads反序列化 只在内存中操作数据 主要用于网络传输 和多个数据与文件打交道
dump序列化 load反序列化 主要用于一个数据直接存在文件里—— 直接和文件打交道
其他参数
Serialize obj to a JSON formatted str.(字符串表示的json对象) Skipkeys:默认值是False,如果dict的keys内的数据不是python的基本类型(str,unicode,int,long,float,bool,None),设置为False时,就会报TypeError的错误。此时设置成True,则会跳过这类key ensure_ascii:,当它为True的时候,所有非ASCII码字符显示为\uXXXX序列,只需在dump时将ensure_ascii设置为False即可,此时存入json的中文即可正常显示。) If check_circular is false, then the circular reference check for container types will be skipped and a circular reference will result in an OverflowError (or worse). If allow_nan is false, then it will be a ValueError to serialize out of range float values (nan, inf, -inf) in strict compliance of the JSON specification, instead of using the JavaScript equivalents (NaN, Infinity, -Infinity). indent:应该是一个非负的整型,如果是0就是顶格分行显示,如果为空就是一行最紧凑显示,否则会换行且按照indent的数值显示前面的空白分行显示,这样打印出来的json数据也叫pretty-printed json separators:分隔符,实际上是(item_separator, dict_separator)的一个元组,默认的就是(‘,’,’:’);这表示dictionary内keys之间用“,”隔开,而KEY和value之间用“:”隔开。 default(obj) is a function that should return a serializable version of obj or raise TypeError. The default simply raises TypeError. sort_keys:将数据根据keys的值进行排序。 To use a custom JSONEncoder subclass (e.g. one that overrides the .default() method to serialize additional types), specify it with the cls kwarg; otherwise JSONEncoder is used.
json 在写入多次dump的时候 不能对应执行多次load来取出数据,pickle可以
json 如果要写入多个元素 可以先将元素dumps序列化,f.write(序列化+'\n')写入文件
读出元素的时候,应该先按行读文件,在使用loads将读出来的字符串转换成对应的数据类型
2.pickle #序列化输出
用法:import pickle
用法也有: dumps和loads 基于内 存中
dump和load #写在文件中
实例化:
import pickle dic = {(190,90,'捏脚'):"大表哥"} f = open('大表哥2','wb') # 使用pickle dump必须以+b的形式打开文件 pickle.dump(dic,f) f.close() 结果: #创建了一个叫'大表哥2'的文件,并传入byte形式的文件
反序列化
import pickle f = open('大表哥2','rb') print(pickle.load(f)) f.close() 结果: {(190, 90, '捏脚'): '大表哥'}
pickle写入多行实例:
import pickle # 关于写多行 dic1 = {"大表哥":(190,90,'捏脚')} dic2 = {"2表哥":(190,90,'捏脚')} dic3 = {"3表哥":(190,90,'捏脚')} f = open('大表哥3','wb') pickle.dump(dic1,f) pickle.dump(dic2,f) pickle.dump(dic3,f) f.close() #读取多行 f = open('大表哥3','rb') #打开文件 while True: try: print(pickle.load(f)) except EOFError: #读取时报错,需要把错误忽略 break
序列化自定义类的对象
例题:
class A: def __init__(self,name,age): self.name=name self.age=age a = A('alex',80) import json # json.dumps(a) #报错json不能序列化类对象 import pickle ret = pickle.dumps(a) print(ret) obj = pickle.loads(ret) print(obj.__dict__) 报错信息如下: Traceback (most recent call last): File "F:/Python-script-2/s11-day25/练习.py", line 50, injson.dumps(a) File "C:\Python36\lib\json\__init__.py", line 231, in dumps return _default_encoder.encode(obj) File "C:\Python36\lib\json\encoder.py", line 199, in encode chunks = self.iterencode(o, _one_shot=True) File "C:\Python36\lib\json\encoder.py", line 257, in iterencode return _iterencode(o, 0) File "C:\Python36\lib\json\encoder.py", line 180, in default o.__class__.__name__) TypeError: Object of type 'A' is not JSON serializable
注销后结果如下:
b'\x80\x03c__main__\nA\nq\x00)\x81q\x01}q\x02(X\x04\x00\x00\x00nameq\x03X\x04\x00\x00\x00alexq\x04X\x03\x00\x00\x00ageq\x05KPub.'
{'name': 'alex', 'age': 80}
模块hashlib —— 摘要算法
#也是一些算法的集合,有好多算法
# 字符串 --> 数字
# 不同的字符串 --> 数字一定不同
# 无论在哪台机器上,在什么时候计算,对相同的字符串结果总是一样的
# 摘要过程不可逆
# 用法
文件的一致性校验
密文验证的时候加密
常用加密算法
md5算法 通用的算法
# sha算法 安全系数更高,sha算法有很多种,后面的数字越大安全系数越高,
# 得到的数字结果越长,计算的时间越长
例:将密码用16进制的加密
import hashlib m = hashlib.md5() m.update('alex3714'.encode('utf-8')) print(m.hexdigest())
现在由于有人讲常用的md5加密过的简单密码进行存储,然后去破解这种,俗称撞库
为了解决这个问题,所以我们想到了一个解决办法,叫做加盐
m = hashlib.md5('wahaha'.encode('utf-8')) #在对hashlib进行实例化的时候,先添加规定的字符串 m.update('123456'.encode('utf-8')) print(m.hexdigest())
还有更安全的动态加盐,就是将用户名动态添加.
username = 'alex' m = hashlib.md5(username[:2:2].encode('utf-8')) #动态截取用户名步长2,0-2的字符串 m.update('123456'.encode('utf-8')) print(m.hexdigest())
经典面试题,
通过这道题能够搞清楚set()集合去重的原理
题意:
# 写一个类 定义100个对象
# 拥有三个属性 name age sex
# 如果两个对象的name 和 sex完全相同
# 我们就认为这是一个对象
# 忽略age属性
# 做这100个对象的去重工作
class Person: def __init__(self,name,age,sex): self.name = name self.age = age self.sex = sex def __hash__(self): return hash(self.name + self.sex) # hash算法本身就存在了 且直接在python中就能调用 # 姓名相同 性别相同的对象的hash值应该相等才行 # 姓名性别都是字符串 def __eq__(self.other): if self.name == other.name and self.sex ==other.sex return Trun obj_lst = [] obj_lst.append(Person('alex',80,'male')) obj_lst.append(Person('alex',70,'male')) obj_lst.append(Person('alex',60,'male')) obj_lst.append(Person('boss_jin',50,'male')) obj_lst.append(Person('boss_jin',40,'male')) obj_lst.append(Person('boss_jin',30,'male')) obj_lst.append(Person('nezha',20,'male')) obj_lst.append(Person('nezha',10,'male')) obj_lst = set(obj_lst)
for obj in obj_lst:print(obj.name)
结论:set对一个对象序列的去重 依赖于这个对象的两个方法 hash eq