第六章 模块
import sys print(sys.argv)
2.第三方模块
别人写好的模块,下载安装使用,如:requests/xlrd
#把pip.exe 所在的目录添加到环境变量中 pip install 要安装的模块名称 #pip install xlrd
3.自定义模块
定义模块时可以把一个py文件或一个文件夹(包)当作一个模块,以方便于以后其他py文件的调用
1.py2:文件中必须有_ _init _ _.py
2.py3:不需要_init _ _.py
def f1():
x1.py文件
#使用自定义模块中的功能 import xxx xxx.f1()
运行
python x1.py
form lizhong import jd jd.f1() form lizhong.jd import f1 f1()
2 from 模块 import 函数 函数() 【as起别名/*】
from lizhongwei import func,show #导入func\show模块 from lizhongwei import func #要注意是否会重名 from lizhongwei import * #导入lizhongwei这个模块的所有功能 func() import lizhongwei
3 form模块 import 函数 as 别名 别名()
from lizhongwei import func as f #要注意是否会重名 def func(): print(123) f()
注意:import是导入一个,from可以导入多层
-
执行的脚本和模块在同一级目录且需要模块中的很多功能时,推荐用:import +模块
-
其他推荐用: from 模块 import 模块 模块 函数()
-
6.3 内置模块
6.3 .1import hashlib
import hashlib def get_md5(data): obj = hashlib.md5() obj.update(data.encode('utf-8')) result = obj.hexdigest() return result val = get_md5('123') print(val)
#加盐 import hashlib def get_md5(data): obj = hashlib.md5('asddghh'.encode('utf-8')) obj.update(data.encode('utf-8')) result = obj.hexdigest() return result val = get_md5('123') print(val)
应用: import hashlib USER_LIST = [] def get_md5(data): obj = hashlib.md5('asddghh'.encode('utf-8')) obj.update(data.encode('utf-8')) result = obj.hexdigest() return result def inner(): print('****用户注册****') while True: user = input('请输入用户名:') if user.upper() == 'N': return pwd = input('请输入密码:') temp = {'username':user,'password':get_md5(pwd)} USER_LIST.append(temp) def login(): print('***用户登录***') user = input('请输入用户名:') pwd = input('请输入密码:') for item in USER_LIST: if item['username'] ==user and item['password'] ==get_md5(pwd): return True inner() result = login() if result: print('登录成功') else: print('登录失败')
import getpass pwd = getpass.getpass('请输入密码:') if pwd == '123': print('输入正确')
6.3.3 sys
python解释器相关的数据:递归次数应用次数
1 sys.getrefcount
import sys #获取一个值的应用计数器 a = [11,22,33] print(sys.getrefcount(a)) #2 指的是引用了几次
2 sys.getrecursionlimit
#python默认支持的最大递归数量 1000 v1 = sys.getrecursionlimit()
3 sys.stdout.write-->print(进度条)
#输入输出 sys.stdout.write('你好') #不换行 import time for i in range(1,101): msg = '%s%%\r'%(i) print(msg,end='') time.sleep(0.05) ''' #进度条 import os import time #读取文件大小(字节) file_size = os.stat('文件').st_size #一点一点的读取文件 read_size = 0 with open('文件名',mode= 'rb') as f,open('a.mp4',mode = 'wb') as f1: while read_size <file_size: churk = f.read(1024)#每次读取1024个字节 f1.write(churk) read_size +=len(churk) val = int(read_size / file_size * 100) #int是为了取整 print('%s%%'%(val),end='')
4 sys.argv 执行脚本传入的参数,让用户执行脚本并传入要删除的文件路径,在内部帮助用户将目录删除
import sys #获取用户执行脚本时传入的参数 #D:\program files\Python37\python37.exe" E:/python/s21day14/sys.py E:/test path = sya.argv[1] #删除目录 import shutil shutil.rmtree(path)
5 sys.path 默认python导入模块时,会按照sys.path路径挨个找
import sys for path in sys.path: #默认python导入模块时,会按照sys.path路径挨个找 print(path) #路径添加到sys.path,然后引用模块的时候可以从这个路径中查找 # import sys # sys.path.append('d:\\') # import 文件名
import shutil shutil.rmtree(path)
2 shutil.move('x.txt','xxx.txt') #重命名
3 shutil.make_archive() 压缩文件
#压缩文件 (zzh表示压缩后的文件名,zip是压缩类型,最后的是需要压缩的文件) #shutil.make_archive('zzh','zip','E:\python\s21\s21day16\src')
4 shutil.unpack_archive() 解压文件
#解压文件 # shutil.unpack_archive('zzh.zip',format = 'zip') #解压到当前目录 # shutil.unpack_archive('zzh.zip',extract_dir='e:\python\xxx',format = 'zip') #解压到指定目录 extract_dit
5 练习题:
import shutil import os from datetime import datetime ctime = datetime.now().strftime('%Y-%m-%d-%H-%M-%S') if not os.path.exists('code'): os.makedirs('code') #1压缩lizhongwei文件夹zip shutil.make_archive(os.path.join('code',ctime),'zip','e:\code') #压缩 #和放在code这个文件夹下 file_path = os.path.join('code',ctime) + '.zip' #绝对路径 shutil.unpack_archive(file_path,r'e"\x1.zip') #解压
-
os.path.exists(path) , 如果path存在,返回True;如果path不存在,返回False
-
os.stat('20190409_192149.mp4').st_size , 获取文件大小
-
os.path.abspath() , 获取一个文件的绝对路径
path = '20190409_192149.mp4' # D:\code\s21day14\20190409_192149.mp4 import os v1 = os.path.abspath(path) print(v1)
1 os.path.dirname ,获取路径的上级目录
import os v = r"D:\code\s21day14\20190409_192149.mp4" print(os.path.dirname(v)
2 os.path.join ,路径的拼接
import os path = "D:\code\s21day14" # user/index/inx/fasd/ v = 'n.txt' result = os.path.join(path,v) print(result) result = os.path.join(path,'n1','n2','n3') print(result)
3 os.listdir , 查看一个目录下所有的文件【第一层】面试题
import os result = os.listdir(r'D:\code\s21day14') for path in result: print(path)
4 os.walk , 查看一个目录下所有的文件【所有层】面试题
import os result = os.walk(r'D:\code\s21day14') for a,b,c in result: # a,正在查看的目录 b,此目录下的文件夹 c,此目录下的文件 for item in c: path = os.path.join(a,item) print(path)
5 补充 --->转义 r
v1 = r"D:\code\s21day14\n1.mp4" (推荐) print(v1) v2 = "D:\\code\\s21day14\\n1.mp4" print(v2)
6 return,break,continue,sys.exit的不同
-
-
break:跳出这个循环,循环不在执行
-
continue:终止当前循环,开始下一次循环
-
sys.exit(),退出程序,程序终止
-
7 os.makedirs 创建文件夹和子目录
#创建一个文件夹和子目录并在在其中写内容 import os file_path = r'eb\xx\xo\xxx.txt' file_folder = os.path.dirname(file_path) if not os.path.exists(file_folder): os.makedirs(file_folder) with open(file_path,mode='w',encoding='utf-8') as f: f.write('dedffg')
8 os.rename 重命名
import os os.rename('eb','db')
json 是一个特殊的字符串。长的像列表/字典/字符串/数字/真假
json格式要求:格式里面只能有int、str、bool、list...,最外层必须得是列表或字典,在json中如果包含字符串必须是双引号
json里面不存在元组,集合
json:优点:所有语言通用;缺点:只能序列化基本的数据类型(列表,字典,int,str...)
v = [11,22,33,{'k1':'v1'},True,'adsg'] import json #序列化,将python的值转换成json格式的字符串 v1 = json.dumps(v) print(v1) #[11, 22, 33, {"k1": "v1"}, true, "adsg"] #反序列化,将json格式的字符串转换成python格式的数据类型 v2= '["delxe",123]' print(type(v2)) v3 = json.loads(v2) print(v3,type(v3))
注意:字典或列表中如有中文想要保留,json序列化的时候可以用ensure_ascii = False
v = {'k1':'李杰'} val = json.dumps(v,ensure_ascii = false) print(val)
import pickle ''' #####dumps/loads,dumps得出来的是字节 v = {1,2,3,4} val = pickle.dumps(v) print(v) data = pickle.loads(val) print(data,type(data)) ''' ''' def f1(): print('f1') v = pickle.dumps(f1) print(v) val = pickle.loads(v) val() ###dump /load v = {1,2,3,4} f = open('x.txt',mode='wb') val = pickle.dump(v,f) f.close() f = open('x.txt',mode='wb') data = pickle.load(f) f.close() print(data)
UTC比GMT更精准 /GMT 格林威治时间 :世界协调时间
本地时间:本地时区的时间
1 time
-
time.time(), 时间戳:1970年1月1日零点经历的秒数 全球总共24个时区
-
time.sleep() 等待秒数
-
time.timezone 时区差异的秒数 和自己所处的位置没有关系和电脑时区设置有关
2 datetime
-
datetime.now() 获取当前本地时间
-
datetime.utcnow() 当前uct时间
-
.strftime () 将datetime格式转换成字符串
-
.strptime() 将字符串转换成datetime格式可用于时间加减
#!/usr/bin/env phthon # -*- coding:utf-8 -*- ''' from datetime import datetime val = datetime.now() #获取当前本地的时间 print(val) #datetime类型 v2 = datetime.utcnow() #当前uct时间 print(v2) ###datetime 类型 ''' ''' from datetime import datetime,timezone,timedelta tz = timezone(timedelta(hours= 7)) #获取某个区的时间,7表示东七区,西区hours是等于负数 v3 = datetime.now(tz) print(v3)##datetime 类型 ''' ###将datetime格式转换成字符串 ''' from datetime import datetime val = datetime.now() print(val) #datetime类型 a = val.strftime('%Y-%m-%d %H:%M:%S') print(a) ''' ####将字符串转换成datetime格式可用于时间加减 ''' from datetime import datetime,timezone,timedelta v1 = datetime.strptime('2011-11-11','%Y-%m-%d') #将字符串转换成datetime v2 = v1 + timedelta(days=40) #加40天 可以是days,hours等,也可以减 print(v2) date = v2.strftime('%Y-%m-%d') #将datetime类型转换成字符串 print(date) ''' ##时间戳和datetime的关系 import time from datetime import datetime,timezone,timedelta ctime = time.time() print(ctime) v1 = datetime.fromtimestamp(ctime) #获取当地的时间 时间戳转datetime print(v1) v1 = datetime.now() val = v1.timestamp() #当前时间转时间戳 print(val)
异常处理可以放在任何地方,但是放的位置不一样有的时候结果也会不一样
基本格式
try: 代码块 except Exception as e: pass
#代码块放在try里面,出现异常就会执行except的内容 try: val = input('请输入数字:') num = int(val) except Exception as e: print('操作异常') def func(a): try: a.strip() except Exception as e: print('处理异常') return False v = func('alex ') print(v)
练习题:
#写函数,函数接收一个列表,将列表中的元素每个都加100 def func(arg): result = [] for item in arg: if item.isdecimal(): result.append(int(item)+100) return result #写函数,接收一个列表,列表中都是url地址,请访问每个地址并获取结果 try的位置不同,结果也不同 import requests def func(url_list): result = [] try: for url in url_list: response = requests.get(url) result.append(response.text) except Exception as e: pass return result func(['http://www.baidu.com','http://google.com','http://www.bing.com']) import requests def func(url_list): result = [] for url in url_list: try: response = requests.get(url) result.append(response.text) except Exception as e: pass return result func(['http://www.baidu.com', 'http://google.com', 'http://www.bing.com'])
#写函数,接收一个列表,列表中都是url地址,请访问每个地址并获取结果 try的位置不同,结果也不同 import requests def func(url_list): result = [] try: for url in url_list: response = requests.get(url) result.append(response.text) except Exception as e: pass return result func(['http://www.baidu.com','http://google.com','http://www.bing.com']) import requests def func(url_list): result = [] for url in url_list: try: response = requests.get(url) result.append(response.text) except Exception as e: pass return result func(['http://www.baidu.com', 'http://google.com', 'http://www.bing.com'])
1 迭代器
自己不会写迭代器,只用
迭代器,对可迭代对象中的元素进行--获取,迭代器对象的内部都有一个_ next _方法,用于以一个个获取数据
-
-
迭代器(帮助你对某种对象[str/int/list/dict/set/tuple】 中的元素进行逐一获取),表现是具有_ next _()且每次调用都会获取可迭代对象中的元素(从前到后一个个获取)
-
#v1 = v.__iter__() v1是一个迭代器 v1 = iter(v)
v = [11,22,33,44] #列表转换成迭代器 v1 = iter(v) #v1 = v.__iter__() val1 = v1.__next__() val2 = v1.__next__() val3 = v1.__next__() val4 = v1.__next__() print(val1,val2,val3,val4) ''' v = [11,22,33,44] v1 = iter(v) while True: try: val = v1.__next__() print(val) except Exception as e: break
-
-
直到遇到报错出现【Stopiteration】就算迭代完了
-
-
第一步将v1转换成迭代器
-
内部反复执行迭代器._ next _()
-
v1 = [11,22,33,44] # 第一步将v1转换成迭代器 #内部反复执行迭代器._ _next_ _() # 取完不报错 for item i v1: print(item)
2可迭代对象
-
-
内部具有_ _ iter_ _()方法的且返回一个迭代器
#v1 = v.__iter__() v1是返回的迭代器 v1 = iter(v)
6.7 生成器(函数的变异)
判断是否是生成器:内部是否有yield
生成器也是特殊的迭代器(生成数据,迭代)
1 生成器函数
#生成器函数(内部是否包含yield) def func(): yield 1 #遇到yield暂停,下次再从它往下开始 yield 2 yield 100 #函数内部代码不执行,返回一个生成器对象 v1 = func() ##生成器是可以被for循环的,一旦开始循环函数内部代码就会开始执行 for item in v1: print(item) #1 2 100
#生成1-100的数 def func(): count = 1 while True: yield count count +=1 if count ==100: return #出现return起到终止循环的作用 val = func() for item in val: print(item) #1 2 3 4 5 .... 边使用边生成 item只拿yield的值
##读文件示例 def func(): ''' 分批去读取文件中的内容,将文件中的内容返回给调用者 ''' # :return: cursor = 0 while True: f = open('db','r',encoding='utf-8') #通过网络连接上redis #代指redis[0:10] f.seek(cursor) data_list = [] for i in range(10): line = f.readline() if not line: return #取完 data_list.append(line) #取10行数据 cursor = f.tell() #取了10行之后的当前位置 f.close() # 关闭与Redis的连接 for row in data_list: yield row yield data_list for item in func(): print(item)
帮助在文件中写内容
只配置一次,多次配置无效
-
-
日志处理本质:Logger/FileHandler/Formatter
-
推荐处理日志方式
import logging file_handler = logging.FileHandler(filename='x1.log', mode='a', encoding='utf-8',)#创建file_handler对象,里面包含日志文件的地址,名称,编码,打开模式,把文件写到哪 logging.basicConfig( format='%(asctime)s - %(name)s - %(levelname)s -%(module)s: %(message)s', datefmt='%Y-%m-%d %H:%M:%S %p', # handlers=[file_handler,], level=logging.ERROR ) logging.error('你好') ##根 file_handler = logging.FileHandler(filename='x1.log', mode='a', encoding='utf-8',) format = logging.Formattor(format='%(asctime)s - %(name)s - %(levelname)s -%(module)s: %(message)s')#format写入的格式 file_handler.setFormatter(format) #- --》创建关系 logger = logging.Logger('xxxx',level = logging.ERROR) logger.addHandler(file_handler)#加载配置后的文件 #addHandler可以加多个 logging.error('你好')
推荐处理日志方式 + 日志分割(通过时间来分割日志)
import time import logging from logging import handlers file_handler = logging.FileHandler(filename='x1.log', mode='a', encoding='utf-8',) file_handler = handlers.TimedRotatingFileHandler(filename='x3.log', when='s', interval=5, encoding='utf-8')#文件名称,when='s', interval=5表示每五秒钟生成一个日志文件, logging.basicConfig( format='%(asctime)s - %(name)s - %(levelname)s -%(module)s: %(message)s', datefmt='%Y-%m-%d %H:%M:%S %p', handlers=[file_handler,], level=logging.ERROR ) for i in range(1,100000): time.sleep(1) logging.error(str(i))
应用场景:对于异常处理捕获到的内容,使用日志模块将其保留到日志文件
# 在应用日志时,如果想要保留异常的堆栈信息。 import logging import requests logging.basicConfig( filename='wf.log', format='%(asctime)s - %(name)s - %(levelname)s -%(module)s: %(message)s', datefmt='%Y-%m-%d %H:%M:%S %p', level=logging.ERROR ) try: requests.get('http://www.xxx.com') except Exception as e: msg = str(e) # 调用e.__str__方法 logging.error(msg,exc_info=True) #exc_info = True 可以保留异常的堆栈信息。
# 记录日志的,给用户和程序员看的 # 用户 :例如:个人银行流水 # 程序员 : # 统计用的 # 用来做故障排除的 debug # 用来记录错误,完成代码的优化的 # logging.basicconfig # 使用方便 # 不能实现中文编码问题;不能同时向文件和屏幕上输出 # logging.debug,logging.warning # logger对象 # 复杂 # 创建一个logger对象 # 创建一个文件操作符 # 创建一个屏幕操作符 # 创建一个格式 # 给logger对象绑定 文件操作符 # 给logger对象绑定 屏幕操作符 # 给文件操作符 设定格式 # 给屏幕操作符 设定格式 import logging logger = logging.getLogger() fh = logging.FileHandler('log.log') #文件操作符 sh = logging.StreamHandler() #屏幕操作符 logger.addHandler(fh) #实例化对象和文件操作符关联,可以绑定多个 logger.addHandler(sh) #实例化对象和屏幕操作符关联 logger.warning('message') #在log.log和运行的屏幕上都可以运行 # 用logger对象来操作 # import logging # logger = logging.getLogger()#创建一个logger对象 fh = logging.FileHandler('log.log')# 创建一个文件操作符 sh = logging.StreamHandler()# 创建一个屏幕操作符 logger.addHandler(fh)# 给logger对象绑定 文件操作符 logger.addHandler(sh)# 给logger对象绑定 屏幕操作符 formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s') # 创建一个格式 fh.setFormatter(formatter) # 给文件操作符 设定格式 sh.setFormatter(formatter)# 给屏幕操作符 设定格式 logger.warning('message')
6.10.1正则规则(元字符,量词)
-
第一条规则:本身是哪一个字符,就匹配字符串中的哪一个字符
正则表达式规则:匹配a :a
需要匹配的字符串:aaaddbbnjj
结果:aaa
- 第二条规则:字符组[字符1字符2],一个字符组就代表匹配一个字符,只要这个字符出现在字符组里,那么就说明这个字符能匹配上
字符组中还可以使用范围 * 所有的范围都必须遵循asii码从小到大来指定 * [0-9] 所有的数字 [a-z] [A-Z] 所有的字母 * 匹配大小写字母[a-zA-z] * 匹配大小写字母和数字[a-zA-z0-9] * 是任意的数字或x[0-9x]-->身份证验证 *[0-9] == \d 表示所有的数字,但字符组还用 * \是转义符,转义符转义了d,让d能够匹配所有的0-9的数 * [\d] [0-9] \d 没有区别,都是匹配一个数字 * [\d\D] [\w\W] [\s\S] 匹配所有一切字符,包括换行符
正则表达式规则 :字符组:既匹配a又匹配b写法[ab] #区别于ab 需要匹配的字符串:aaaddbbnjj 结果:aaabb
元字符
* \w 表示大小写字母 数字 下划线 * \s 表示空白 换行符 制表符 * \t 匹配字表符 * \n 匹配换行符 * \D 表示所有的非数字 * \W 表示除数字 字母 下划线除外的所有字符 * \S 表示非空白 * . 表示除了换行符之外的任意内容 * [ ]字符组:只要在中括号内的所有字符都是符合规则的字符 * [ ^]非字符组:只要在中括号内的所有字符都是不符合规则的字符 * ^ 表示一个字符的开始 * $ 表示一个字符的结束 * |表示或,注意: 如果两个规则有重叠部分,总是长的在前面,短的在后面 * ()表示分组,给一部分正则规定为一组,|这个符合的作用域就可以缩小了
量词
* {n} 表示只能出现n次,例手机号码:1[3-9]\d{9} * {n,}表示至少出现n次 * {n,m}表示至少出现n次,至多出现m次 * ?表示匹配0次或1次 表示可有可无,但是有只能有一个,比如小数点 * ‘+’ 加号表示匹配一次或多次 * ‘*’ * 表示匹配0次或多次 表示可有可无,但是又可以有多个,比如小数点后n位
例题
匹配任意的2位整数: \d{2} 匹配任意的保留两位小数的数字:\d+\.\d{2} 匹配一个整数或者小数 \d+\.\d+|\d+ \d+\.?\d* \d+(\.\d+)?
默认贪婪匹配:总是会在符合量词条件的范围内尽量多匹配
# <.+> # <html>adljdkjsljdlj</html>sddsdff 匹配到<html>adljdkjsljdlj</html>--》回溯算法
非贪婪匹配:惰性匹配:总是匹配符合条件范围内尽量小的字符串,在量词后+?
元字符+量词+?x :表示按照元字符规则在量词范围内匹配,一旦遇到x就停止
.*?x 匹配任意的内容任意多次遇到x就立即停止,?的意思是值是否是要找的x
-
-
re.search 匹配包含
-
re.match 从头开始匹配
-
re.complie 在同一个正则表达式重复使用多次的时候使用能够减少时间的开销,
-
# print('\\\\n') # print('\\n') # print(r'\\n') # print(r'\n') #正则表达式中是\\n匹配\n # 正则表达式中的转义符在python的字符串中也刚好有转移的作用 # 但是正则表达式中的转义符和字符串中的转义符并没关系 # 且还容易有冲突 # 为了避免这种冲突 # 我们所有的正则都以在工具中的测试结果为结果 # 然后只需要在正则和待匹配的字符串外面都加r即可
import re # regex # ret = re.findall('\d+','alex83') # print(ret) #['83'] # findall 会匹配字符串中所有符合规则的项 # 并返回一个列表 # 如果未匹配到返回空列表
# ret = re.search('\d+','alex83') # print(ret) # 如果能匹配上返回一个对象,如果不能匹配上返回None # if ret: # print(ret.group()) #8 如果是对象,那么这个对象内部实现了group,所以可以取值 # # 如果是None,那么这个对象不可能实现了group方法,所以报错 # group会从头到尾从待匹配字符串中取出第一个符合条件的项,如果匹配到了,返回一个对象,用group取值,如果没匹配到,返回None,不能用group
#re.match # ret = re.match('\d','alex83') == re.match('^\d','alex83') # print(ret) #none ret = re.match('\d','83alex') if ret: print(ret.group()) #8 # 会从头匹配字符串中取出从第一个字符开始是否符合规则 # 如果符合,就返回对象,用group取值 # 如果不符合,就返回None # match = search + ^正则
import re import os import json import datetime import xlrd import requests class Person(object): pass class Uese(object): pass class run(): pass if __name__== '__main__' run()
-
-
多可执行文件