一
# 时间模块优先掌握的操作 # 一:time # 时间分为三种格式: # 1、时间戳(timestape):从1970年到现在经过的秒数 # 作用:用于时间间隔的计算 # print(time.time()) # 2、格式化的时间字符串(format string): 按照某种格式显示的时间:2020-03-30 11:11:11 # 作用:用于展示时间 # time.strftime('%Y-%m-%d %H:%M:%S %p') # time.strftime('%Y-%m-%d %X') # 3、结构化的时间(struct_time) # 作用:用于单独获取时间的某一部分 # res=time.localtime() # 本地时区的struct_time # tm_year=, tm_mon=, tm_mday=, tm_hou=, tm_min=, tm_sec=, tm_wday(一年中第几周)=, tm_yday(一年中第几天)=, tm_isdst(夏令时)= # print(res.tm_yday) # time.gmtime # UTC时区的struct_time # 二:datetime import datetime # print(datetime.datetime.now()) -> 2020-03-30 14:52:31.833672 # 作用:用来进行时间运算 # print(datetime.datetime.now() + datetime.timedelta(days=3)) #datetime.timedelta 用来盛放需要增加或减少的时间 # print(datetime.datetime.now() + datetime.timedelta(weeks=1)) # 时间模块需要掌握的操作 # 1、时间格式的转换 # struct_time->时间戳 import time # s_time=time.localtime() # print(time.mktime(s_time)) # 时间戳->struct_time # tp_time=time.time() # print(time.localtime(tp_time)) # print(time.gmtime(333333333)) # struct_time->格式化的字符串形式的时间 # s_time=time.localtime() # print(time.strftime('%Y-%m-%d %H:%M:%S',s_time)) # 格式化字符形式的时间->struct time # print(time.strptime('1988-03-03 11:11:11','%Y-%m-%d %H:%M:%S')) # format string<------>timestamp (重点掌握) # '1988-03-03 11:11:11'+7 # format string--->struct_time--->timestamp # struct_time=time.strptime('1988-03-03 11:11:11','%Y-%m-%d %H:%M:%S') # timestamp=time.mktime(struct_time)+7*86400 # print(timestamp) # format string<---struct_time<---timestamp # res=time.strftime('%Y-%m-%d %X',time.localtime(timestamp)) # print(res) # time.sleep(3) # 了解知识 # import time # print(time.asctime()) 把一个表示时间的元祖或struct_time表示为:sun jun 20 23:21:05 1993 这种形式 # import datetime # print(datetime.datetime.now()) # print(datetime.datetime.utcnow()) # 世界标准时间 print(datetime.datetime.fromtimestamp(333333)) # 时间戳直接转换为格式字符形式的日期 # import random 随机取数 # print(random.random()) #(0,1)----float 大于0且小于1之间的小数 # print(random.randint(1, 3)) # [1,3] 大于等于1且小于等于3之间的整数 # print(random.randrange(1, 3)) # [1,3) 大于等于1且小于3之间的整数 # print(random.choice([111, 'aaa', [4, 5]])) # 1或者23或者[4,5] # print(random.sample([111, 'aaa', 'ccc','ddd'],2)) # 列表元素任意2个组合 # print(random.uniform(1, 3)) # 大于1小于3的小数,如1.927109612082716 # item = [1, 3, 5, 7, 9] # random.shuffle(item) # 打乱item的顺序,相当于"洗牌" # print(item) # 应用:随机验证码 # import random # # res='' # for i in range(6): # 从26大写字母中随机取出一个=chr(random.randint(65,90)) chr[65]~chr[90] 参考的ASCII码表,对应A~Z # 从10个数字中随机取出一个=str(random.randint(0,9)) # # 随机字符=random.choice([从26大写字母中随机取出一个,从10个数字中随机取出一个]) # res+=随机字符 import random def make_code(size=4): res = '' for i in range(size): s1 = chr(random.randint(65, 90)) s2 = str(random.randint(0, 9)) res += random.choice([s1, s2]) return res print(make_code(6)) # import os # 获取某一个文件夹下所有的子文件以及子文件夹的名字 # res=os.listdir('.') # print(res) # 返回path的大小 # size=os.path.getsize(r'/Users/linhaifeng/PycharmProjects/s14/day22/01 时间模块.py') # print(size) # os.remove() 删除一个文件 # os.rename("oldname","newname") 重命名文件/目录 # 运行系统命令:应用程序向操作系统发送系统调用运行相关命令 # os.system("dir r'C:\a'") # 得到一个字典,规定:key与value必须都为字符串 # os.environ['aaaaaaaaaa']='111' 获取系统环境变量,范围更广 # print(os.environ) # print(os.path.dirname(r'/a/b/c/d.txt')) # print(os.path.basename(r'/a/b/c/d.txt')) 返回path最后的文件名 # print(os.path.isfile(r'笔记.txt')) 当前文件夹下是否存在文件 # print(os.path.isdir(r'aaa')) 当前文件夹下是否存在文件夹 # print(os.path.join('a','/','b','c','d')) path拼接 # 三种获得上上一层文件夹路径的方法 # BASE_DIR=os.path.dirname(os.path.dirname(__file__)) 推荐这种 # print(BASE_DIR) # normpath 规范化路径 # BASE_DIR=os.path.normpath(os.path.join(__file__,# '..',# '..'# )) # 在python3.5之后,推出了一个新的模块pathlib # from pathlib import Path # res = Path(__file__).parent.parent # print(res) # res=Path('/a/b/c') / 'd/e.txt' # print(res) # print(res.resolve()) # import sys # python3.8 run.py 1 2 3 # sys.argv 命令行参数别表,第一个元素是路径本身,用来接收外面传进来的值,也就是获取解释器后的参数值 # print(sys.argv) # 【案例 文件copy脚本】 # import os # src_file=sys.argv[1] # dst_file=sys.argv[2] # def copy_file(): # if not os.path.isfile(src_file): # print('请输入正确的源文件路径') # rutern # if not os.path.isfile(dst_file): # print('请输入正确的目标文件路径') # return # with open(r'%s' %src_file,mode='rb') as read_f, # open(r'%s' %dst_file,mode='wb') as write_f: # for line in read_f: # write_f.write(line) # python3.8 run.py src_file dst_file # # 【案例:模拟下载及打印进度条】 import time def progress(percent): if percent > 1: percent = 1 res = int(50 * percent) * '#' print(' [%-50s] %d%%' % (res, int(100 * percent)), end='') recv_size = 0 total_size = 1025011 while recv_size < total_size: time.sleep(0.01) recv_size += 1024 # 打印进度条 percent = recv_size / total_size # 1024 / 333333 progress(percent) # # shutil(了解) # import shutil # # shutil.copyfileobj(open('old.xml', 'r'), open('new.xml', 'w')) # # 将文件内容拷贝到另一个文件中 # # shutil.copyfile('f1.log', 'f2.log') # 目标文件无需存在 拷贝文件 # # shutil.copymode('f1.log', 'f2.log') # 目标文件必须存在 仅拷贝权限。内容、组、用户均不变 # # shutil.copystat('f1.log', 'f2.log') # 目标文件必须存在 仅拷贝状态的信息,包括:mode bits, atime, mtime, flags # # shutil.copy('f1.log', 'f2.log') # # 拷贝文件和权限 # # shutil.copy2('f1.log', 'f2.log') # # 拷贝文件和状态信息 # # shutil.copytree('folder1', 'folder2', ignore=shutil.ignore_patterns('*.pyc', 'tmp*')) # # 目标目录不能存在,注意对folder2目录父级目录要有可写权限,ignore的意思是排除 递归的去拷贝文件夹 # # shutil.rmtree('folder1') # # 递归的去删除文件 # # shutil.move('folder1', 'folder3') # # 递归的去移动文件,它类似mv命令,其实就是重命名。 # # # # 将 /data 下的文件打包放置当前程序目录 # import shutil # # ret = shutil.make_archive("data_bak", 'gztar', root_dir='/data') # # # 将 /data下的文件打包放置 /tmp/目录 # import shutil # # ret = shutil.make_archive("/tmp/data_bak", 'gztar', root_dir='/data') # # # # shutil # # 对压缩包的处理是调用 # # ZipFile # # 和 # # TarFile # # 两个模块来进行的,详细: # import tarfile # # # 压缩 # t = tarfile.open('/tmp/egon.tar', 'w') # t.add('/test1/a.py', arcname='a.bak') # t.add('/test1/b.py', arcname='b.bak') # t.close() # 解压 t = tarfile.open('/tmp/egon.tar', 'r') t.extractall('/egon') t.close() # tarfile压缩解压缩
二. 序列化
一、json 与 pickle 模块 # 1、什么是序列化&反序列化 #序列化:把对象从内存中变成可存储或者传输的类型发生的过程 #反序列化:把这种序列化得到的类型再转变成之前的类型 # 内存中的数据类型---->序列化---->特定的格式(json格式或者pickle格式) # 内存中的数据类型<----反序列化<----特定的格式(json格式或者pickle格式) # 土办法: # {'aaa':111}--->序列化str({'aaa':111})----->"{'aaa':111}" # {'aaa':111}<---反序列化eval("{'aaa':111}")<-----"{'aaa':111}" # 2、为何要序列化 # 序列化得到的结果=>特定的格式的内容有两种用途 # 1、可用于存储=》用于存档 # 2、传输给其他平台使用=》跨平台数据交互 # 强调: # 存储用的特定格式:专用的格式=》pickle,只有python可以识别 # 传输用的特定格式:一种通用、能够被所有语言识别的格式=》json # 3、如何序列化与反序列化 # 示范1 # import json # # 序列化 # json_res=json.dumps([1,'aaa',True,False]) # # 反序列化 # l=json.loads(json_res) # 示范2: import json # 序列化的结果写入文件的复杂方法 # json_res=json.dumps([1,'aaa',True,False]) # print(json_res,type(json_res)) # "[1, "aaa", true, false]" # with open('test.json',mode='wt',encoding='utf-8') as f: # f.write(json_res) # 将序列化的结果写入文件的简单方法 # with open('test.json',mode='wt',encoding='utf-8') as f: # json.dump([1,'aaa',True,False],f) # 从文件读取json格式的字符串进行反序列化操作的复杂方法 # with open('test.json',mode='rt',encoding='utf-8') as f: # json_res=f.read() # l=json.loads(json_res) # print(l,type(l)) # 从文件读取json格式的字符串进行反序列化操作的简单方法 # with open('test.json',mode='rt',encoding='utf-8') as f: # l=json.load(f) # print(l,type(l)) # json验证: json格式兼容的是所有语言通用的数据类型,不能识别某一语言的所独有的类型 # json.dumps({1,2,3,4,5}) #集合读不出来 # json强调:一定要搞清楚json格式,不要与python混淆 # l=json.loads('[1, "aaa", true, false]') # l=json.loads("[1,1.3,true,'aaa', true, false]") #json 不识别单引号 # print(l[0]) # 了解 #在python解释器2.7与3.6之后都可以json.loads(bytes类型),唯独3.5不可以 # l = json.loads(b'[1, "aaa", true, false]') # print(l, type(l)) # with open('test.json',mode='rb') as f: # l=json.load(f) # res=json.dumps({'name':'哈哈哈'}) # 中文字符序列化后的形式=> "u54c8u54c8u54c8" # print(res,type(res)) # 4、猴子补丁 # 在入口处打猴子补丁 # import json # import ujson # def monkey_patch_json(): # json.__name__ = 'ujson' # json.dumps = ujson.dumps # json.loads = ujson.loads # monkey_patch_json() # 在入口文件处运行 # import ujson as json # 不行,导入的还是ujson # 5.pickle模块 import pickle # res=pickle.dumps({1,2,3,4,5}) # print(res,type(res)) # s=pickle.loads(res) # print(s,type(s)) 二、configparser 模块 用configparser 对settings文件进行读取 文件格式如下: [section1] k1 =v1 [section2] k2 : v2 age = 18 import configparser # 1、获取sections # print(config.sections()) # 2、获取某一section下的所有options # print(config.options('section1')) # 3、获取items # print(config.items('section1')) # 4、获取某一sections下指定的options # res=config.get('section1','user') # print(res,type(res)) 三、hashlib 模块 # 1、什么是哈希hash # hash一类算法,该算法接受传入的内容,经过运算得到一串hash值 # hash值的特点: #I 只要传入的内容一样,得到的hash值必然一样 #II 不能由hash值返解成内容 #III 不管传入的内容有多大,只要使用的hash算法不变,得到的hash值长度是一定 # 2、hash的用途 # 用途1:特点II用于密码密文传输与验证 # 用途2:特点I、III用于文件完整性校验 # 3、如何用 # import hashlib # # m=hashlib.md5() # m.update('hello'.encode('utf-8')) # windows 系统默认是GBK # m.update('world'.encode('utf-8')) # res=m.hexdigest() # 'helloworld' # print(res) # 模拟撞库 # cryptograph='aee949757a2e698417463d47acac93df' # import hashlib # # 制作密码字段 passwds=[ 'alex3714', 'alex1313', 'alex94139413', 'alex123456', '123456alex', 'a123lex', ] # dic={} # for p in passwds: # res=hashlib.md5(p.encode('utf-8')) # dic[p]=res.hexdigest() # # # 模拟撞库得到密码 # for k,v in dic.items(): # if v == cryptograph: # print('撞库成功,明文密码是:%s' %k) # break # 提升撞库的成本=>密码加盐 import hashlib m=hashlib.md5() m.update('天王'.encode('utf-8')) m.update('alex3714'.encode('utf-8')) m.update('盖地虎'.encode('utf-8')) print(m.hexdigest()) # 文件的完整性校验 # m.update(文件所有的内容) # m.hexdigest() # with open('a.txt',mode='rb') as f: # f.seek(0,10) # f.read(10) 四、subprocess 模块 import subprocess obj=subprocess.Popen('路径',shell=True, stdout=subprocess.PIPE,stderr=subprocess.PIPE,) # stdout:标准正确输出 pipe:管道 stderr:错误输出 # print(obj) # res=obj.stdout.read() # print(res.decode('gbk')) err_res=obj.stderr.read()
三 日志 re
# 三 # 一、logging 模块 import logging logging.basicConfig( # 1、日志输出位置:1、终端 2、文件 filename='access.log', # 不指定,默认打印到终端 # 2、日志格式 format='%(asctime)s - %(name)s - %(levelname)s -%(module)s: %(message)s', # 3、时间格式 datefmt='%Y-%m-%d %H:%M:%S %p', # 4、日志级别 # critical => 50 # error => 40 # warning => 30 # info => 20 # debug => 10 level=10, ) logging.debug('调试debug') # 10 logging.info('消息info') # 20 logging.warning('警告warn')# 30 logging.error('egon提现失败') # 40 logging.critical('严重critical') # 50 """ 日志配置字典LOGGING_DIC """ # 1、定义三种日志输出格式,日志中可能用到的格式化串如下 # %(name)s Logger的名字 # %(levelno)s 数字形式的日志级别 # %(levelname)s 文本形式的日志级别 # %(pathname)s 调用日志输出函数的模块的完整路径名,可能没有 # %(filename)s 调用日志输出函数的模块的文件名 # %(module)s 调用日志输出函数的模块名 # %(funcName)s 调用日志输出函数的函数名 # %(lineno)d 调用日志输出函数的语句所在的代码行 # %(created)f 当前时间,用UNIX标准的表示时间的浮点数表示 # %(relativeCreated)d 输出日志信息时,自Logger创建以来的毫秒数 # %(asctime)s 字符串形式的当前时间。默认格式是 “2003-07-08 16:49:45,896”。逗号后面的是毫秒 # %(thread)d 线程ID。可能没有 # %(threadName)s 线程名。可能没有 # %(process)d 进程ID。可能没有 # %(message)s用户输出的消息 # 2、强调:其中的%(name)s为getlogger时指定的名字 standard_format = '%(asctime)s - %(threadName)s:%(thread)d - 日志名字:%(name)s - %(filename)s:%(lineno)d -' '%(levelname)s - %(message)s' simple_format = '[%(levelname)s][%(asctime)s][%(filename)s:%(lineno)d]%(message)s' test_format = '%(asctime)s] %(message)s' # 3、日志配置字典 LOGGING_DIC = { 'version': 1, #版本 'disable_existing_loggers': False, #禁用现有的记录器 'formatters': { #定制不同的日志格式对象,绑定给不同的handler对象使用 'standard': { 'format': standard_format }, 'simple': { 'format': simple_format }, 'test': { 'format': test_format }, }, 'filters': {}, #过滤日志的对象 # handlers是日志的接收者,不同的handler会将日志输出到不同的位置 'handlers': { #打印到终端的日志 'console': { 'level': 'DEBUG', 'class': 'logging.StreamHandler', # 打印到屏幕 'formatter': 'simple' }, 'default': { 'level': 'DEBUG', 'class': 'logging.handlers.RotatingFileHandler', # 保存到文件,日志轮转 'maxBytes': 1024*1024*5, # 日志大小 5M 'backupCount': 5, # 备份计数 'filename': 'a1.log', # os.path.join(os.path.dirname(os.path.dirname(__file__)),'log','a2.log') 'encoding': 'utf-8', 'formatter': 'standard', }, #打印到文件的日志,收集info及以上的日志 'other': { 'level': 'DEBUG', 'class': 'logging.FileHandler', # 保存到文件 'filename': 'a2.log', # os.path.join(os.path.dirname(os.path.dirname(__file__)),'log','a2.log') 'encoding': 'utf-8', 'formatter': 'test', }, }, # loggers是日志的产生者,产生的日志会传递给handler然后控制输出 'loggers': { #logging.getLogger(__name__)拿到的logger配置 #name是loggers子子典当中的key 'kkk': { 'handlers': ['console','other'], # 这里把上面定义的两个handler都加上,即log数据既写入文件又打印到屏幕 'level': 'DEBUG', # loggers(第一层日志级别关限制)--->handlers(第二层日志级别关卡限制) 'propagate': False, # 默认为True,向上(更高level的logger)传递,通常设置为False即可,否则会一份日志向上层层传递 }, '终端提示': { 'handlers': ['console',], 'level': 'DEBUG', 'propagate': False, }, '': { 'handlers': ['default', ], 'level': 'DEBUG', 'propagate': False, }, }, } # 4、应用 import settings # 1、logging是一个包,需要使用其下的config、getLogger,可以如下导入 # from logging import config # from logging import getLogger # 2、也可以使用如下导入 import logging.config # 这样连同logging.getLogger都一起导入了,然后使用前缀logging.config. # 3、加载配置 logging.config.dictConfig(settings.LOGGING_DIC) # 4、拿到日志的产生者即loggers来产生日志 # logger1=getLogger('kkk') # logger1.info('这是一条info日志') # logger2=getLogger('终端提示') # logger2.info('logger2产生的info日志') # logger3=getLogger('用户交易') # logger3.info('logger3产生的info日志') # logger4=getLogger('用户常规') #当getLogger取不到对象是,默认使用key=''的配置 # logger4.info('logger4产生的info日志') # 5、补充两个重要额知识 # 1、日志名的命名 # 日志名是区别日志业务归属的一种非常重要的标识 # 2、日志轮转 # 日志记录着程序员运行过程中的关键信息,所以不能随意删,为了避免放在同一个日志文件中造成文件过大,加载缓慢, # 需要一种设定,超出限制后会将之前的内容写到另一个文件中,当前文件只剩新内容 # (实际上老文件是做了重命名用来保存老内容,然后再生成一个新的空文件,命名为原名,保存新内容) # 二、re 模块 import re # print(re.findall('Aalex',' alexis alex sb')) ==>[] 字符串开头是空格 # # print(re.findall('sb',' alexis alexsb sb')) # # print(re.findall('sb',"""alex # alexis # alex # sb # """)) ==> [] 只匹配到换行前的结束字符串 # print(re.findall('sb$',"""alex # alexis # alex # sb # """)) ==> ['sb'] # print(re.findall('^alex$','alexis alex sb')) # print(re.findall('^alex$','al ex')) # print(re.findall('^alex$','alex')) ==>混用时必须完全一样才能匹配 # 重复匹配:| . | * | ? | .* | .*? | + | {n,m} | # 1、.:匹配除了 之外任意一个字符,指定re.DOTALL之后才能匹配换行符 # print(re.findall('a.b','a1b a2b a b abbbb a b a b a*b')) # a.b # ['a1b','a2b','a b','abb','a b','a*b'] # print(re.findall('a.b','a1b a2b a b abbbb a b a b a*b',re.DOTALL)) # 2、*:左侧字符重复0次或无穷次,性格贪婪 # print(re.findall('ab*','a ab abb abbbbbbbb bbbbbbbb')) # ab* #['a','ab','abb','abbbbbbbb'] # 3、+:左侧字符重复1次或无穷次,性格贪婪 # print(re.findall('ab+','a ab abb abbbbbbbb bbbbbbbb')) # ab+ # 4、?:左侧字符重复0次或1次,性格贪婪 # print(re.findall('ab?','a ab abb abbbbbbbb bbbbbbbb')) # ab? # ['a','ab','ab','ab'] # 5、{n,m}:左侧字符重复n次到m次,性格贪婪 # {0,} => * # {1,} => + # {0,1} => ? # {n}单独一个n代表只出现n次,多一次不行少一次也不行 # print(re.findall('ab{2,5}','a ab abb abbb abbbb abbbbbbbb bbbbbbbb')) # ab{2,5} # ['abb','abbb','abbbb','abbbbb] # print(re.findall('d+.?d*',"asdfasdf123as1111111.123dfa12adsf1asdf3")) # []匹配指定字符一个 # print(re.findall('adb','a1111111b a3b a4b a9b aXb a b a b',re.DOTALL)) ['a3b', 'a4b', 'a9b'] # print(re.findall('a[501234]b','a1111111b a3b a4b a9b aXb a b a b',re.DOTALL)) ['a3b', 'a4b'] # print(re.findall('a[0-9a-zA-Z]b','a1111111b axb a3b a1b a b a b',re.DOTALL)) ['axb', 'a3b', 'a1b', ] # print(re.findall('a[^0-9a-zA-Z]b','a1111111b axb a3b a1b a0b a4b a9b aXb a b a b',re.DOTALL)) ['a b', 'a b'] ^表示非 # print(re.findall('a[-0-9 ]b','a-b a0b a1b a8b aXb a b a b',re.DOTALL)) ['a-b', 'a0b', 'a1b', 'a8b', 'a b']