注意:生成时间都是生成的当前时间 其中计算机认识的时间只能是’时间戳’格式,而程序员可处理的或者说人类能看懂的时间有: ‘格式化的时间字符串’,‘结构化的时间’ ,于是有了下图的转换关系: 结构化时间和格式化字符串时间的转换: 用途:用于时间的加减 注意:所有的动态的实现都是静态的快速替换 部分代码疑点剖析: 超出百分百: 序列化的结果–> 我们都应该都明白一个公司的一个软件,一定是使用了较长时间的,很有可能其中使用了多种编程语言,编程语言有各自负责的一个模块, 强调: 疑问解答:json格式可以用于存储吗? 实验总结: (3)中的序列化、反序列化和文件处理的源代码可以简化的。如下: 猴子补丁,是针对模块,进行打补丁的一种思想方法。 pickle模块中的方法的使用和json模块大致一样, Pickle的问题和所有其他编程语言特有的序列化问题一样,就是它只能用于Python,并且可能不同版本的Python彼此都不兼容,因此,只能用Pickle保存那些不重要的数据,不能成功地反序列化也没关系。 用途:configparser模块专门用来获取配置文件中的配置信息的。 客户端,用户会输入账号、密码,实现登录,账号密码的传输不可能采用明文传输吧,被别人抓包分析,账号密码直接就暴露了,因此需要加密,把账号密码一起hash得到一个hash值,传给服务端,对比hash值是否一样即可。 但 既然这种简单hash可以比较容易破解,那么就只能 hash算法就像一座工厂,工厂接收你送来的原材料(可以用m.update()为工厂运送原材料),经过加工返回的产品就是hash值 虽然现实是账号密码一起hash,这里文章目录
一、time与datetime模块
1、time模块
(1)三种格式时间生成
在Python中,通常有这几种方式来表示时间:
import time #--------------------------我们先以当前时间为准,让大家快速认识三种形式的时间 print(time.time()) # 时间戳:1487130156.419527 print(time.strftime("%Y-%m-%d %X")) #格式化的时间字符串:'2017-02-15 11:40:53' print(time.localtime()) #本地时区的struct_time print(time.gmtime()) #UTC时区的struct_time
三种时间格式的转换
结构化时间和时间戳之间的转换:
# 时间戳-->结构化时间 >>> time.localtime(time.time()) # 执行结果:time.struct_time(tm_year=2020, tm_mon=5, tm_mday=15, tm_hour=10, tm_min=20, tm_sec=15, tm_wday=4, tm_yday=136, tm_isdst=0) >>> time.gmtime(time.time()) # 结构化时间-->时间 >>> time.mktime(time.localtime()) # 执行结果:1589510093.0
>>> time.strftime("%Y-%m-%d %X", time.localtime()) # 执行结果:'2020-05-15 10:48:47' >>> time.strptime('2011-05-05 16:37:06', '%Y-%m-%d %X') # 执行结果:time.struct_time(tm_year=2011, tm_mon=5, tm_mday=5, tm_hour=16, tm_min=37, tm_sec=6, tm_wday=3, tm_yday=125, tm_isdst=-1)
2、datetime模块
import datetime # 明确datetime.datetime.now()返回的究竟是个什么东西? >>> datetime.datetime.now() # 我们暂时称之为datetime格式时间,这种格式并不是那三种格式之一,不要被print误导! datetime.datetime(2020, 5, 15, 11, 7, 14, 505326) >>> print(datetime.datetime.now()) # 这是print做了优化。不要被误导。 2020-05-15 11:08:11.641439 #只取datetime格式时间的年月日 >>> datetime.date.fromtimestamp(time.time()) datetime.date(2020, 5, 15) >>> print(datetime.date.fromtimestamp(time.time())) # 执行结果依然被print优化了 2020-05-15 #时间加减 print(datetime.datetime.now() ) print(datetime.datetime.now() + datetime.timedelta(3)) #当前时间+3天 print(datetime.datetime.now() + datetime.timedelta(-3)) #当前时间-3天 print(datetime.datetime.now() + datetime.timedelta(hours=3)) #当前时间+3小时 print(datetime.datetime.now() + datetime.timedelta(minutes=30)) #当前时间+30分 # 时间修改 >>> c_time = datetime.datetime.now() >>> c_time.replace(minute=3,hour=2) #分钟改为3分,小时改为2点 datetime.datetime(2020, 5, 15, 2, 3, 32, 602746)
二、random模块
1、基本用法
>>> import random # 随机生成小数 >>> random.random() # (0,1)----float 大于0且小于1之间的小数 >>> random.uniform(1,3) # 大于1小于3的小数,如1.927109612082716 #随机生成整数 >>> random.randint(1,3) # [1,3] 大于等于1且小于等于3之间的整数 >>> random.randrange(0,100,2) # [0,100) 步长为2,0,2,4...,在这个里面产生随机数,即100以内的随机偶数 # 其他用法 >>> random.choice([1,'23',[4,5]]) # 1或者23或者[4,5] >>> random.sample([1,'23',[4,5]],2) # 列表元素任意2个组合 >>> item=[1,3,5,7,9] >>> random.shuffle(item) #打乱item的顺序,相当于"洗牌"
2、生成随机验证码
import random def make_code(n): res = '' for i in range(n): num = str(random.randint(1,9)) # 生成随机1-9,并强转成字符串格式 char = chr(random.randint(65,90)) # 生成随机a-z字母 get_str = random.choice([num,char]) # 从生成的数字和字母选择一个进行字符串拼接 res += get_str return res verti_code = make_code(5) print(verti_code)
3、打印进度条(random模拟文件下载网速波动)
(1)打印进度条预备知识:格式化字符串
#进度条长度控制为50个%s >>> print('[%+50s]' %'#') # '+'代表右对齐,可简化省略'+' [ #] >>> print('[%50s]' %'#') # 其中还是在传%s,中间的50代表[]中间的字符串长度,且没有传值的用空格代替,且默认为右对齐 [ #] >>> print('[%-50s]' %'#') # '-'代表左对齐,给%s传一个值'#' [# ]
# 把进度条长度写活 >>> '[%%-%ds]' %(50) # 第二个%号代表取消第一个%的特殊意义,所以最后只有一个%,%%相当于转义%,因此这里的%s不会被传值,因此被传值的是%d '[%-50s]' >>> ('[%%-%ds]' %(50)) %('##') # 相当于'[%-50s]' %('##') '[## ]'
(2)打印进度条实现
import time import random # 定义打印进度条函数 def progress(percent,width=50): if percent > 1: percent = 1 show_str = ('[%%-%ds]' %(width)) %(int(percent*width)*'#') # 进度条字符串 # 打印进度条,且后面加上文件下载百分比 print('r%s %.1f%%' %(show_str,percent*100),end='') # end = '':不换行打印;r:从行首开始打印;%.1f:传进来的浮点数取一位小数 # 下载文件 recv_size = 0 # 代表下载接收到的数据量 total_size = 150000 # 代表文件总大小,单位为字节 while recv_size < total_size: time.sleep(random.random()) # random模拟网速波动,也可以用其他uniform方法指定区间波动加快速度 recv_size += 1024 # 0.2秒下载1kb percent = recv_size/total_size # 获取当前下载文件的比例(小数) progress(percent,70)
if percent > 1: percent = 1 # 因为用recv_size += 1024模拟下载文件大小,这样子,只要下载的文件大小不是1024倍数,最后就会出现超过百分百的情况,因此这里做个判断percent大于1,如果大于1,那么就percent = 1,直接下完。
有人会问,有
%-50s
控制字符的长度(即#的个数),为什么还会出现超过50个字符长度?答:%-50s,并不是强制约束了传入进来的字符串长度为50(或者说'#'号个数),而是说传进来的'######'这个字符串,左对齐,然后除这个长度以外的我都用'空格'占位,传进来的超过这个长度,只是不再有空格占位罢了!
三、json&pickle模块
1、什么是序列化和反序列化?
# 内存中的数据类型 --> 序列化 --> 特定的格式(json或pickle格式) # 特定的格式(json或pickle格式)--> 反序列化 --> 内存中的数据类型
2、为何要用序列化?
特定的格式的内容有两种用途
各编程语言之间会有数据交互,怎么解决?
python java 列表 --> 特定的格式 --> 数组
pickle格式只能python使用
格式的要求应该是一种通用的、能够被所有语言识别的格式
答:不能,json格式只是把所有语言共有的一些数据类型提取出来做了通用格式,python的集合就无法转成json格式。因此需要用python专用的pickle格式。
3、json模块实现序列化、反序列化
(1)序列化
>>> import json >>> res = json.dumps([1,'吴晋丞',True]) >>> res '[1, "\u5434\u664b\u4e1e", true]' >>> type(res) <class 'str'> # 注意: 1. json格式最后得到的都是一个字符串,而且必须用''(单引号)引起来,且里面内容的字符串类型只能用""(双引号)表示字符串,例如:'["\u5434\u664b\u4e1e"]' 2. json格式里面对中文做了处理,但这个"\u5434\u664b\u4e1e"并不是任何一种编码格式,只是中文的json格式,要想显示中文,必须进行反序列化 3. python中布尔值True、False,json格式中都变成小写
(2)反序列化
>>> str is bytes True >>> load = json.loads(res) # res是字符串类型,这里传入还可以是bytes类型 >>> load [1, '吴晋丞', True] >>> type(load) <class 'list'>
(3)序列化、反序列化与文件处理结合
# 源代码 import json with open('db.txt','wb') as f: res = json.dumps([1,'吴晋丞',True]) f.write(res.encode('utf-8')) # 不能以字符串形式write进文件,除非用t模式 with open('db.txt','rb') as f: json_res = f.read() print(json.loads(json_res)) print(json_res,type(json_res)) print('-------------------------------------------------------') print(json.loads(json_res.decode('utf-8'))) print(json_res.decode('utf-8'),type(json_res.decode('utf-8'))) # 执行结果 [1, '吴晋丞', True] b'[1, "\u5434\u664b\u4e1e", true]' <class 'bytes'> ------------------------------------------------------- [1, '吴晋丞', True] [1, "u5434u664bu4e1e", true] <class 'str'>
在python解释器2.7与3.6之后都可以json.loads(bytes类型),但唯独3.5不可以
# 多行数据的文件的反序列化 import json with open('db.txt','wb') as f: res = json.dumps([1,'吴晋丞',True]) + 'n' # 不加n不会换行,下面的for循环会出错 res1 = json.dumps([2, 'haha', False]) f.write(res.encode('utf-8')) f.write(res1.encode('utf-8')) with open('db.txt','rb') as f: for i in f: json_res = json.loads(i) print(json_res) # 执行完程序db.txt的内容(文件是多行数据): [1, "u5434u664bu4e1e", true] [2, "haha", false] # 执行结果: [1, '吴晋丞', True] [2, 'haha', False]
(4)json模块的dump和load函数实现代码简化
# b模式因为要先生成json格式,再编码,因此无法使用dump函数 import json with open('db.txt','wb') as f: res = json.dumps([1,'吴晋丞',True]) f.write(res.encode('utf-8')) with open('db.txt','rb') as f: json_res = json.load(f) # 直接将整个文件反序列化,因此文件只能有一个数据;如果有多个数据,且一行为一个数据,则还是需要用loads,(3)中有多行数据文件的源代码。 print(json_res)
# t模式,因为dumps函数生成的就是字符串可以用t模式直接写入文件,因此不需要编码,因此可以使用dump函数 import json with open('db.txt','w') as f: json.dump([1,'吴晋丞',True],f) with open('db.txt','r') as f: print(json.load(f)) # 直接将整个文件反序列化,因此文件只能有一个数据
4、猴子补丁
如果模块中有些方法你觉得写的并不好,你要用自己写的方法,替换此模块中对应的方法,但不改变模块源代码
。就要用到猴子补丁。# 原monkey模块中的方法 def other_func(): print("from other_func") def hello(): print('hello') def world(): print('world') # 你自己认为更好的方法 # 自己写的monkey_plus模块里的方法 def hello(): print('hello everyone !') def world(): print('This world is beautiful !') #以后写python项目会有很多python程序文件,不可能一个个打补丁,因此,只需要在程序入口打个补丁,后面所有其他程序文件,用的依旧是补丁版的monkey。 # 下面是运行程序文件。需要调用monkey模块,且还要给monkey模块打补丁,注意打补丁一般在程序入口处打补丁 import monkey import monkey_plus def monkey_patch_monkey(): monkey.hello = monkey_plus.hello monkey.world = monkey_plus.world monkey_patch_monkey() # 其实这种场景也比较多, 比如我们引用团队通用库里的一个模块, 又想丰富模块的功能, 除了继承之外也可以考虑用Monkey Patch(猴子补丁). # 采用猴子补丁之后,如果发现优化后的模块使用效果不符合预期,那也可以快速撤掉补丁(不调用打补丁的函数即可)。个人感觉Monkey Patch带了便利的同时也有搞乱源代码的风险!
5、pickle模块实现序列化、反序列化
有一个不同之处:dumps函数的返回值的数据类型不一样
,请看下面:# 序列化与反序列化: import pickle res = pickle.dumps({1,'吴晋丞'}) # 集合 print(pickle.loads(res),type(res)) # 运行结果:{1, '吴晋丞'} <class 'bytes'> # json模块的dumps的返回值是一个字符串,而pickle模块的dumps的返回值是一个bytes类型。 # 文件处理与序列化与反序列化(b模式): import pickle with open('db.txt','wb') as f: pickle.dump([1],f) # 相当于f.write(pickle.dumps({1,'吴晋丞'})) with open('db.txt','rb') as f: print(pickle.load(f)) # 相当于pickle.loads(f.read()) # 不能使用t模式,只能使用b模式,因为dumps返回值是bytes类型,t模式无法接收bytes类型数据
6、python2与python3的pickle兼容性问题
# coding:utf-8 import pickle with open('a.pkl',mode='wb') as f: # 一:在python3中执行的序列化操作如何兼容python2 # python2不支持protocol>2,默认python3中protocol=4 # 所以在python2中dump操作应该指定protocol=2 pickle.dump('你好啊',f,protocol=2) with open('a.pkl', mode='rb') as f: # 二:python3中反序列化才能正常使用 res=pickle.load(f) print(res)
四、configparser模块
configparser模块支持的配置文件格式如下:# 注释1 ; 注释2 [section1] k1 = v1 k2:v2 # :号相当于=号 user=egon age=18 is_admin=true salary=31 [section2] k1 = v1
1、获取配置文件信息(重点)
import configparser config=configparser.ConfigParser() config.read('a.cfg') #查看所有的标题 res=config.sections() #['section1', 'section2'] print(res) #查看标题section1下所有key=value的key options=config.options('section1') print(options) #['k1', 'k2', 'user', 'age', 'is_admin', 'salary'] #查看标题section1下所有key=value的(key,value)格式 item_list=config.items('section1') print(item_list) #[('k1', 'v1'), ('k2', 'v2'), ('user', 'egon'), ('age', '18'), ('is_admin', 'true'), ('salary', '31')] #查看标题section1下user的值=>字符串格式 val=config.get('section1','user') print(val) #egon #查看标题section1下age的值=>整数格式 val1=config.getint('section1','age') print(val1) #18 #查看标题section1下is_admin的值=>布尔值格式 val2=config.getboolean('section1','is_admin') print(val2) #True #查看标题section1下salary的值=>浮点型格式 val3=config.getfloat('section1','salary') print(val3) #31.0
2、修改配置文件信息
import configparser config=configparser.ConfigParser() config.read('a.cfg',encoding='utf-8') #删除整个标题section2 config.remove_section('section2') #删除标题section1下的某个k1和k2 config.remove_option('section1','k1') config.remove_option('section1','k2') #判断是否存在某个标题 print(config.has_section('section1')) #判断标题section1下是否有user print(config.has_option('section1','')) #添加一个标题 config.add_section('egon') #在标题egon下添加name=egon,age=18的配置 config.set('egon','name','egon') config.set('egon','age',18) #报错,必须是字符串 #最后将修改的内容写入文件,完成最终的修改 config.write(open('a.cfg','w'))
五、hashlib模块
1、hash介绍
1. 什么叫hash? hash是一种算法(3.x里代替了md5模块和sha模块,主要提供 SHA1, SHA224, SHA256, SHA384, SHA512 ,MD5 算法),该算法接受传入的内容,经过运算得到一串hash值 2. hash值的特点是: * 只要传入的内容一样,得到的hash值必然一样 =====> 要用明文传输密码文件完整性校验 * 不能由hash值反解成内容 =======> 把密码做成hash值,不应该在网络传输明文密码 * 只要使用的hash算法不变,无论校验的内容有多大,得到的hash值长度是固定的
也可以通过撞库破解hash得到密码
,抓包得到一个账号与密码的hash值,然后预先有个数据库,里面存着常用的密码,然后把数据库里的一个个密码与账号hash,把得到的hash值和抓包的hash值对比,直到得到一样的,就破解成功了。如果你账号都不晓得,还破解个屁!!!
采用密码加盐进行hash。这样一般来说都非常不容易破解。
2、hash应用
(1)hash基本应用
# hashlib模块的用法 import hashlib m=hashlib.md5() # m=hashlib.sha256(),指定需要使用的hash算法 m.update('hello'.encode('utf8')) m.update('world'.encode('utf8')) print(m.hexdigest()) #92a7e713c30abbb0319fa07da2a5c4af # 可以多次输送原材料,最后一起hash。相当于m.update('helloworld'.encode('utf8'))
(2)模拟撞库
为了验证的简单,我就只是密码进行hash,然后撞库。
import hashlib passwds=[ # 某人账号常用密码 'alex3714', 'alex1313', 'alex94139413', 'alex123456', '123456alex', 'a123lex', ] def make_passwd_dic(passwds): dic={} for passwd in passwds: m=hashlib.md5() m.update(passwd.encode('utf-8')) dic[passwd]=m.hexdigest() return dic def break_code(cryptograph,passwd_dic): for k,v in passwd_dic.items(): if v == cryptograph: print('密码是===>