我的python学习之路-递归/内置函数/模块/正则
本节内容:
一、递归函数
1.2 练习题
二、内置函数
三、模块
3.9 tarfile 模块 后缀为.tar | .tar.gz | .tar.bz2
四、正则表达式
一、 递归函数
定义:自己调用自己的函数,就是递归函数
递:去 归:回 一去一回是递归
1、基本写法
def digui(n): print(n,"<----start---->") if n>0: digui(n-1) print(n,"<-----end----->") digui(5)
代码解析:
去的过程:
n = 5 print(5,"<--start-->") if 5 > 0 digui(n - 1) => digui(4) 代码阻塞在第13行
n = 4 print(4,"<--start-->") if 4 > 0 digui(n - 1) => digui(3) 代码阻塞在第13行
n = 3 print(3,"<--start-->") if 3 > 0 digui(n - 1) => digui(2) 代码阻塞在第13行
n = 2 print(2,"<--start-->") if 2 > 0 digui(n - 1) => digui(11 代码阻塞在第13行
n = 1 print(1,"<--start-->") if 1 > 0 digui(n - 1) => digui(0) 代码阻塞在第13行
n = 0 print(0,"<--start-->") if 0 > 0 条件不满足 print(0,"<--end-->")
[如果最后一层函数执行结束,将触发归的过程,把没执行完的代码执行结束.]
归的过程:
n = 1 走到上一次代码阻塞13行的位置,往下走 print(1,"<--end-->")
n = 2 走到上一次代码阻塞13行的位置,往下走 print(2,"<--end-->")
n = 3 走到上一次代码阻塞13行的位置,往下走 print(3,"<--end-->")
n = 4 走到上一次代码阻塞13行的位置,往下走 print(4,"<--end-->")
n = 5 走到上一次代码阻塞13行的位置,往下走 print(5,"<--end-->")
栈帧空间:函数调用时,每次调用都会在内存中独立开辟一个空间,叫做栈帧空间,
是独立的副本,空间和空间之间数据不共享
总结:
(1)递归就是不停的开辟和不停的释放栈帧空间的过程,整合在一起时递归
(2)触发递归函数归的过程有两种:
(1) 递归在最后一层栈帧空间代码全部执行结束的时候,触发归的过程
(2) 遇到函数中的return,回到上一层栈帧空间从阻塞处继续向下执行
(3) 在写递归时,务必给与递归跳出的条件,不能无限递归下去,否则内存溢出,蓝屏死机
(4) 如果递归的层次太深,不建议使用递归;(官方说法1000层,因个人电脑而已
2、练习题
1.使用递归完成任意数n的阶乘
def jiecheng(n): if 0<= n <=1: return 1 return n * jiecheng(n-1)
代码解析
1 ''' 2 去的过程: 3 n = 5 return n * jiecheng(n-1) => return 5 * jiecheng(4) 4 n = 4 return n * jiecheng(n-1) => return 4 * jiecheng(3) 5 n = 3 return n * jiecheng(n-1) => return 3 * jiecheng(2) 6 n = 2 return n * jiecheng(n-1) => return 2 * jiecheng(1) 7 n = 1 return 1 8 9 归的过程: 10 n = 2 return n * jiecheng(n-1) => return 2 * 1 11 n = 3 return n * jiecheng(n-1) => return 3 * 2 * 1 12 n = 4 return n * jiecheng(n-1) => return 4 * 3 * 2 * 1 13 n = 5 return n * jiecheng(n-1) => return 5 * 4 * 3 * 2 * 1 14 所有代码执行结束 : 返回 return 5 * 4 * 3 * 2 * 1 => 120 15 '''
2.使用尾递归完成任意数n的阶乘
尾递归: 自己调用自己,且非表达式
特点 : 计算的结果在参数中运算;
def jiecheng(n,endval): if n <= 1: return endval return jiecheng(n-1,n*endval) print(jiecheng(5,1))
尾递归的特点:最后一层函数调用结束后的返回值,就是最顶级函数调用的结果,
所以我们的思维逻辑只考虑递去的过程即可,归的思维逻辑可以不考虑了;
需要在写递归时,在参数运算时动脑筋;
代码解析:
1 """ 2 代码去的过程: 3 n = 5 , endval = 1 if n <= 1: 条件不成立 return jiecheng(5-1,5*1) => jiecheng(4,5*1) 4 n = 4 , endval = 5*1 if n <= 1: 条件不成立 return jiecheng(4-1,4*5*1) => jiecheng(3,4*5*1) 5 n = 3 , endval = 4*5*1 if n <= 1: 条件不成立 return jiecheng(3-1,3*4*5*1) => jiecheng(2,3*4*5*1) 6 n = 2 , endval = 3*4*5*1 if n <= 1: 条件不成立 return jiecheng(2-1,2*3*4*5*1) => jiecheng(1,2*3*4*5*1) 7 n = 1 , endval = 2*3*4*5*1 if n <= 1: 条件成立 return endval [2*3*4*5*1] 8 9 递归归的过程: 10 最后一层结果就是函数顶级调用的结果.一深直入; 11 12 """
尾递归在一些特别的解释器中,每次调用函数时,都只在内存中开辟一个栈帧空间,
后者替换前者,只要最后一层空间有数据返回,直接结束.
但是目前cpython解释器不支持,仍然是有去有回;
优化代码
# 优化代码1 def jiecheng(n,endval=1): if n <= 1: return endval return jiecheng(n-1,n*endval) print(jiecheng(5,1)) # 优化代码2 def outer(n): def jiecheng(n,endval=1): if n <= 1: return endval return jiecheng(n-1,n*endval) return jiecheng(5,1) print(outer(5))
3.使用递归完成斐波那契数列
def feb(n): if n == 1 or n == 2: return 1 # 寻找上一个值 + 寻找上上个值 return feb(n - 1) + feb(n - 2) print(feb(5))
二、内置函数
1、abs 绝对值函数
res = abs(-1) print(res)
2、round 四舍五入
(n.5 n为偶数则舍去 n.5 n为奇数,则进一!)
res = round(3.69)#4 res = round(3.5)#4 res = round(4.5) #4 res = round(4.51)#5
3、sum 计算一个序列的和
lst =[1,2,3,4]
res = sum(lst)
4、max min 获取一个序列里边的最大值 最小值
lst = [100,200,20,-3]
# max 获取一个序列里边的最大值
res = max(lst)
# min 获取一个序列里边的最小值
res = min(lst)
print(res
其他方法
lst = sorted(lst) maxval = lst[-1] minval = lst[0] print(maxval,minval)
max与min的高阶用法与sorted相同
return 最终返回的数据和传入到自定义函数中的数据是一致的
container = {"何子豪":100,"李雅琪":200,"王雨涵":300} def func(n): print(container[n]) # 返回的是年龄,按照年龄找到最大值最小值 return container[n] res = max(container,key=func) res = min(container,key=func) print(res)
5、pow 计算某个数值的x次方
# pow 计算某个数值的x次方 res = pow(2,3) # 前2个参数的结果和第三个参数取余 res = pow(2,3,5) print(res)
6、进制转化函数
# bin 将10进制数据转化为二进制 res = bin(255) print(res) # oct 将10进制数据转化为八进制 res = oct(8) print(res) # hex 将10进制数据转化为16进制 res = hex(255) print(res)
7、字符和ASCII转化函数
# chr 将ASCII编码转换为字符 res = chr(97) print(res) # ord 将字符转换为ASCII编码 res = ord("a") print(res)
8、字符串转换成Python代码函数
# eval 将字符串当作python代码执行 (慎用) strvar = "print(123434343434)" strvar = "a=100" # print(strvar) # eval(strvar) error # exec 将字符串当作python代码执行(功能更强大) (慎用) strvar = "a=100" strvar = """ for i in range(50): print(i) """ exec(strvar)
9、repr 不转义字符输出字符串 [等价于元字符串]
pathvar = "D:\notepadd++\t" print(repr(pathvar))
10、hash 生成哈希值
res1 = hash("a") res2 = hash("a") print(res1,res2)
三、模块
1、数学模块 math
1 import math 2 #ceil() 向上取整操作 (对比内置round) *** 3 res = math.ceil(3.1) 4 res = math.ceil(-3.5) 5 print(res) 6 7 #floor() 向下取整操作 (对比内置round) *** 8 res = math.floor(4.199) 9 res = math.floor(-4.199) 10 print(res) 11 12 #pow() 计算一个数值的N次方(结果为浮点数) (对比内置pow) *** 13 res = math.pow(2,3) 14 # math中的pow方法没有三个参数,只有2个; 15 # res = math.pow(2,3,2) error 16 print(res) 17 18 #sqrt() 开平方运算(结果浮点数) *** 19 res = math.sqrt(9) 20 print(res) # 3.0 21 22 #fabs() 计算一个数值的绝对值 (结果浮点数) (对比内置abs) 23 res = math.fabs(-999) 24 print(res) 25 26 #modf() 将一个数值拆分为整数和小数两部分组成元组 27 res = math.modf(3.567) 28 print(res) 29 30 #copysign() 将参数第二个数值的正负号拷贝给第一个 (返回一个小数) 31 res = math.copysign(-18,-19) 32 print(res) 33 34 #fsum() 将一个容器数据中的数据进行求和运算 (结果浮点数)(对比内置sum) 35 lst = [1,2,3,4] 36 print(math.fsum(lst)) 37 38 #圆周率常数 pi *** 39 res = math.pi 40 print(res)
2、随机模块 random
1、random() 获取随机0-1之间的小数(左闭右开)
import re res = random.random() print(res)
2、randrange() 随机获取指定范围内的整数(包含开始值,不包含结束值,间隔值)
# 一个参数 res = random.randrange(5) print(res) # 二个参数 res = random.randrange(1,7) print(res) # 三个参数 res = random.randrange(1,10,3) # 1 4 7 print(res)
3、randint() 随机产生指定范围内的随机整数 (了解)
res = random.randint(1,4) # 留头留尾 print(res)
4、uniform() 获取指定范围内的随机小数(左闭右开)
res = random.uniform(2,4) # 2 <= x < 4 res = random.uniform(4,2) # 2 < x <= 4 print(res)
5、choice() 随机获取序列中的值(多选一)
lst = ["耿择时","孙翔宇","家营和","张银"] res = random.choice(lst) print(res
6、sample() 随机获取序列中的值(多选多) [返回列表]
lst = ["耿择时","孙翔宇","家营和","张银"] res = random.sample(lst,2) print(res) # 返回列表
7、shuffle() 随机打乱序列中的值(直接打乱原序列)
lst = [1,2,3,4,45,5,6] random.shuffle(lst) print(lst) #[3, 5, 4, 6, 45, 2, 1]
8、验证码功能
1 def yanzhengma(): 2 strvar = "" 3 for i in range(4): 4 # 元素中包含数字 5 num = str(random.randrange(10)) 6 # 元素中含有小写字母 7 s_c = chr(random.randrange(97,123)) 8 # 元素中含有大写字母 9 b_c = chr(random.randrange(65,91)) 10 # 把可能的元素扔到列表中,随机抽 11 lst = [num,s_c,b_c] 12 # 把随机抽取的4次内容都叠加到字符串strvar中 13 strvar += random.choice(lst) 14 return strvar
3、 pickle 序列化模块
序列化: 把不能够直接存储的在文件中的数据变得可存储
反序列化 :把存储的数据拿出来恢复成原来的数据类型
需要配合文件操作 使用 dump 和 load
不需要配合文件操作 使用 dumps 和 loads
1、dump 把对象序列化后写入到file-like Object(即文件对象)
lst = [1,12,3,4] with open("ceshi1.txt",mode="wb") as fp: pickle.dump(lst,fp)
2、load 把file-like Object(即文件对象)中的内容拿出来,反序列化成原来数据
with open("ceshi1.txt",mode="rb") as fp: res = pickle.load(fp) print(res,type(res))
3、dumps 把任意对象序列化成一个bytes
# 序列化函数 def func(): print("我是func函数 ... ") res = pickle.dumps(func) print(res)
4、loads 把任意bytes反序列化成原来数据
# 反序列化函数字节流 func = pickle.loads(res) func()
5、使用dumps 和 loads 将数据存储到文件中
with open("ceshi1.txt",mode="wb") as fp: res1 = pickle.dumps(it) fp.write(res1) with open("ceshi1.txt",mode="rb") as fp: res = fp.read() it = pickle.loads(res) print(next(it)) print(next(it))
4、json 模块
所有编程语言都能够识别的数据格式叫做json,是字符串
能够转换的数据格式 : int float bool str list tuple dict None
json : 一般用来做数据的传输,序列化成字符串
pickle : 一般用来做数据的存储,序列化成字节流
1.json 的用法
(1)json中的 dumps 和 loads
dic = {"name":"于盛林","age":25,"sex":"男性","family":["老于","小鱼","小小鱼"]} # 序列化 # ensure_ascii=False 显示中文 , sort_keys=False 对字典的键进行排序 res = json.dumps(dic,ensure_ascii=False,sort_keys=True) print(res , type(res)) # 反序列化 dic = json.loads(res) print(dic, type(dic))
(2)json中的 dump 和 load
with open("ceshi2.txt",mode="w",encoding="utf-8") as fp: json.dump(dic,fp,ensure_ascii=False) with open("ceshi2.txt",mode="r",encoding="utf-8") as fp: dic = json.load(fp) print(dic,type(dic))
2.json 和 pickle 之间的区别
(1)json
json可以连续dump , 但是不能连续的load
load是一次性把所有数据拿出来反序列化成原来的数据类型
1 """ 2 dic1 = {"a":1,"b":2} 3 dic2 = {"c":3,"d":4} 4 # 连续dump 5 with open("ceshi3.txt",mode="w",encoding="utf-8") as fp: 6 json.dump(dic1,fp) 7 fp.write("\n") 8 json.dump(dic2,fp) 9 fp.write("\n") 10 11 # 连续load error 12 """ 13 with open("ceshi3.txt",mode="r",encoding="utf-8") as fp: 14 json.load(fp) 15 json.load(fp) 16 """ 17 # 解决 18 with open("ceshi3.txt",mode="r",encoding="utf-8") as fp: 19 for i in fp: 20 dic = json.loads(i) 21 print(dic, type(dic))
(2)pickle
pickle可以连续dump , 也能连续的load
1 import pickle 2 dic1 = {"a":1,"b":2} 3 dic2 = {"c":3,"d":4} 4 # 连续dump 5 with open("ceshi4.txt",mode="wb") as fp: 6 pickle.dump(dic1,fp) 7 pickle.dump(dic2,fp) 8 9 # 连续load 10 with open("ceshi4.txt",mode="rb") as fp: 11 dic1 = pickle.load(fp) 12 print(dic1 , type(dic1)) 13 dic2 = pickle.load(fp) 14 print(dic2 , type(dic2))
一次性把所有数据全部拿取出来
with open("ceshi4.txt",mode="rb") as fp: try: while True: dic = pickle.load(fp) print(dic , type(dic)) except: pass
(3)json 和 pickle 两个模块的区别
(1)json序列化之后的数据类型是str,所有编程语言都识别,
但是仅限于(int float bool)(str list tuple dict None)
json不能连续load,只能一次性拿出所有数据
(2)pickle序列化之后的数据类型是bytes,
所有数据类型都可转化,但仅限于python之间的存储传输.
pickle可以连续load,多套数据放到同一个文件中
5、time 时间模块
1 import time 2 #time() 获取本地时间戳 3 res = time.time() 4 print(res) 5 6 # localtime => mktime => ctime 7 # 返回元组 => 返回时间戳 => 时间字符串 8 # 1.localtime() 获取本地时间元组 (参数是时间戳,默认当前) 9 res = time.localtime() 10 print(res) 11 # 指定时间戳 12 ttp = time.localtime(1600000000) 13 print(ttp) 14 15 # 2.mktime() 通过时间元组获取时间戳 (参数是时间元组) 16 ttp = (2020,12,9,11,5,59,0,0,0) 17 res = time.mktime(ttp) 18 print(res) 19 20 # 3.ctime() 获取本地时间字符串(参数是时间戳,默认当前) 21 res = time.ctime() 22 print(res) 23 24 # 指定时间戳 25 res = time.ctime(1607483245) 26 print(res) 27 28 29 #asctime() 通过时间元组获取时间字符串(参数是时间元组) (了解) 30 """不能自动识别周几""" 31 ttp = (2020,12,9,11,5,59,0,0,0) 32 res = time.asctime(ttp) 33 print(res) 34 35 # 解决办法: 36 res = time.mktime(ttp) # 变成时间戳 37 time_str = time.ctime(res) # 变成时间字符串; 38 print(time_str) 39 40 #sleep() 程序睡眠等待 41 # time.sleep(2) 42 # print("我睡醒了") 43 44 45 46 # 注意:=> strftime 时间元组 => 时间字符串 47 # 4.strftime() 格式化时间字符串(格式化字符串,时间元组) 48 """linux支持中文显示,windows默认不支持""" 49 res = time.strftime("你好 :%Y-%m-%d %H:%M:%S ") 50 print(res) 51 52 # 指定时间元组格式化字符串; 53 ttp = (2021,12,9,11,5,59,0,0,0) 54 res = time.strftime("你好 :%Y-%m-%d %H:%M:%S " , ttp) 55 print(res) 56 57 # 注意:=> strptime 时间字符串 => 时间元组 58 # 5.strptime() 将时间字符串通过指定格式提取到时间元组中(时间字符串,格式化字符串) 59 """字符串必须严丝合缝,不能随便加空格;否则报错""" 60 strvar1="著名的NBA球星霍华德的生日是2020年12月8号,在家里的泳池中下午15点30分40秒开派对" 61 strvar2="著名的NBA球星霍华德的生日是%Y年%m月%d号,在家里的泳池中下午%H点%M分%S秒开派对" 62 res = time.strptime(strvar1,strvar2) 63 print(res) 64 65 66 #perf_counter() 用于计算程序运行的时间 (了解) 67 startime = time.time() 68 # startime = time.perf_counter() 69 for i in range(10000000): 70 pass 71 endtime = time.time() 72 # endtime = time.perf_counter() 73 print("用的时间是{}".format(endtime-startime))
6、压缩模块zipfile (后缀为zip)
1 import zipfile 2 3 4 # 1.创建压缩包 5 # (1)打开压缩包 6 zf = zipfile.ZipFile("ceshi100.zip","w",zipfile.ZIP_DEFLATED) 7 # zf.write(路径,别名) 8 # (2)写入文件 9 zf.write("/bin/chmod","chmod") 10 zf.write("/bin/cat","cat") 11 zf.write("/bin/chown","tmp/chown") 12 # (3)关闭文件 13 zf.close() 14 15 16 # 2.解压文件 17 zf = zipfile.ZipFile("ceshi100.zip","r") 18 # 解压所有 extractall(路径) 19 # zf.extractall("ceshi100") 20 zf.extract("cat","ceshi200") 21 zf.close() 22 23 24 # 3.查看压缩包 支持with语法 (自动实现close操作,不需要手动) 25 with zipfile.ZipFile("ceshi100.zip","r") as zf: 26 lst = zf.namelist() 27 print(lst) 28 29 30 # 4.追加文件 31 with zipfile.ZipFile("ceshi100.zip","a",zipfile.ZIP_DEFLATED) as zf: 32 zf.write("/bin/ln","ln")
1 def progress(percent): 2 # 如果传入的比例超过100% ,强制等于100%; 3 if percent > 1: 4 percent = 1 5 strvar = int(50 * percent) * "#" 6 print("\r[%-50s] %d%%" % (strvar , percent * 100),end="") 7 8 recv_data = 0 9 total = 1024 10 while recv_data < total: 11 # 延迟0.1秒 12 time.sleep(0.1) 13 recv_data += 100 14 # 比例 = 接受数据的大小 / 总大小 15 percent = recv_data / total 16 # 把比例扔给progress,显示实际的进度条效果; 17 progress(percent)
7、OS模块 对系统进行操作
1 import os 2 #system() 在python中执行系统命令 3 # os.system("touch 1.txt") 4 # os.system("ipconfig") 5 # os.system("ifconfig") 6 7 #popen() 执行系统命令返回对象,通过read方法读出字符串 8 # obj = os.popen("ifconfig") 9 # res = obj.read() 10 # print(res) 11 12 #listdir() 获取指定文件夹中所有内容的名称列表 13 lst = os.listdir(".") 14 print(lst) 15 16 #getcwd() 获取当前文件所在的默认路径 17 # 路径 18 res = os.getcwd() 19 print(res) 20 21 # 路径 + 文件 22 print(__file__) 23 24 #chdir() 修改当前文件工作的默认路径 25 os.chdir("/home/wangwen/mysoft/") 26 # os.system("mkdir ceshi100") 27 os.system("rm -rf ceshi100") 28 29 #environ 获取或修改环境变量 30 print(os.environ) 31 print(os.environ["PATH"]) 32 os.environ["PATH"] += ":/home/wangwen/mysoft" 33 os.system("wangwen") 34 35 36 #--os 模块属性 37 #name 获取系统标识 linux,mac ->posix windows -> nt 38 print(os.name) 39 40 #sep 获取路径分割符号 linux,mac -> / window-> \ 41 res = "wangwen"+ os.sep + "notepad" 42 print(repr(res)) 43 44 #linesep 获取系统的换行符号 linux,mac -> \n window->\r\n 或 \n 45 print(repr(os.linesep))
1 import os 2 os.chdir("/home/wangwen/mysoft/") 3 4 os.mknod 创建文件 (windows目前版本还存在兼容性问题,等待版本迭代;) 5 os.mknod("lianxi.py") 6 os.remove 删除文件 7 os.remove("lianxi.py") 8 os.mkdir 创建目录(文件夹) 9 os.mkdir("abc_ww") 10 os.rmdir 删除目录(文件夹) 11 os.rmdir("abc_ww") 12 os.rename 对文件,目录重命名 13 os.rename("lianxi1","lianxi2") 14 os.makedirs 递归创建文件夹 15 os.makedirs("a/b/c/d/e/f/g") 16 os.removedirs 递归删除文件夹(空文件夹) 17 os.removedirs("a/b/c/d/e/f/g")
1 import os,time 2 3 pathvar = "/mnt/hgfs/day17/abc.py" 4 #basename() 返回文件名部分 5 res = os.path.basename(pathvar) 6 print(res) 7 #dirname() 返回路径部分 8 res = os.path.dirname(pathvar) 9 print(res) 10 11 print(__file__) # /mnt/hgfs/python33_gx/day17/3.py 12 res = os.path.dirname(__file__) 13 print(res) 14 15 #split() 将路径拆分成单独的文件部分和路径部分 组合成一个元组 16 tup = os.path.split(pathvar) 17 print(tup) 18 19 #join() 将多个路径和文件组成新的路径 可以自动通过不同的系统加不同的斜杠 linux / windows\ 20 path1 = "home" 21 path2 = "wangwen" 22 path3 = "mysoft" 23 # 方法一 24 pathvar = path1 + os.sep + path2 + os.sep + path3 25 print(pathvar) 26 # 方法二(推荐) 27 pathvar = os.path.join(path1,path2,path3) 28 print(pathvar) 29 30 #splitext() 将路径分割为后缀和其他部分 (了解) 31 pathvar = "/mnt/hgfs/.day17/abc.py" 32 res = os.path.splitext(pathvar) 33 print(res) 34 35 res = pathvar.split(".") 36 print(res[-1]) 37 38 #getsize() 获取文件的大小 *** 39 """getsize只能获取文件大小,不能获取文件夹的大小""" 40 print(os.getcwd()) 41 pathvar = os.path.join(os.getcwd(),"1.txt") # /mnt/hgfs/python33_gx/day17/1.txt 42 print(pathvar) 43 res = os.path.getsize(pathvar) 44 print(res) 45 46 #isdir() 检测路径是否是一个文件夹 *** 47 pathvar = os.path.join(os.getcwd(),"1.txt") # /mnt/hgfs/python33_gx/day17/1.txt 48 res = os.path.isdir(pathvar) 49 print(res) 50 #isfile() 检测路径是否是一个文件 *** 51 res = os.path.isfile(pathvar) 52 print(res) 53 #islink() 检测路径数否是一个链接 ** 54 res = os.path.islink("/home/wangwen/ceshi03/ceshi01") 55 print(res) 56 57 58 os.chdir("/home/wangwen/mysoft/") 59 """ stat 文件 => 查看相应的时间 """ 60 #getctime() [windows]文件的创建时间,[linux]权限的改动时间(返回时间戳) ** 61 res = os.path.getctime("ceshi2.py") 62 print(res) 63 #getmtime() 获取文件最后一次修改时间(返回时间戳) ** 64 res = os.path.getmtime("ceshi2.py") 65 print(res) 66 #getatime() 获取文件最后一次访问时间(返回时间戳) ** 67 res = os.path.getatime("ceshi2.py") 68 print(res) 69 # 返回时间字符串 70 str_time = time.ctime(res) 71 print(str_time) 72 73 #exists() 检测指定的路径是否存在 *** 74 res = os.path.exists("ceshi4.py") 75 print(res) 76 77 78 79 #isabs() 检测一个路径是否是绝对路径 *** 80 pathvar = "." 81 res = os.path.isabs(pathvar) 82 print(res) 83 84 #abspath() 将相对路径转化为绝对路径 *** 85 res = os.path.abspath(pathvar) 86 print(res) 87 88 # 如果不是绝对路径 => 变成绝对路径 89 """/开头的是绝对路径,剩下的都是相对路径;""" 90 pathvar = "ceshi3.py" 91 if not os.path.isabs(pathvar): 92 res = os.path.abspath(pathvar) 93 print(res)
8、shutil模块 复制/移动/
1 # 1.复制内容 2 # copyfileobj(fsrc, fdst[, length=16*1024]) 复制文件 (length的单位是字符(表达一次读多少字符)) (了解) 3 """ 4 fp1 = open("lianxi2",mode="r+",encoding="utf-8") 5 fp2 = open("ceshi1.txt",mode="w",encoding="utf-8") 6 shutil.copyfileobj(fp1,fp2) 7 """ 8 # copyfile(src,dst) #单纯的仅复制文件内容 , 底层调用了 copyfileobj (了解) 9 shutil.copyfile("ceshi1.txt","ceshi3.py") 10 11 # 2.复制权限 12 # copymode(src,dst) #单纯的仅复制文件权限 , 不包括内容 (虚拟机共享目录都是默认777) 13 """复制权限时,必须文件存在""" 14 shutil.copymode("ceshi3.py","lianxi2") 15 16 # copystat(src,dst) #复制所有状态信息,包括权限,组,用户,修改时间等,不包括内容 17 shutil.copystat("lianxi2","ceshi4.py") 18 19 # 3.复制内容 + 权限 20 # copy(src,dst) #复制文件权限和内容 21 shutil.copy("lianxi2","ceshi5.py") 22 23 # copy2(src,dst) #复制文件权限和内容,还包括权限,组,用户,时间等 24 shutil.copy2("lianxi2","ceshi6.py") 25 26 # 4.递归拷贝/删除 27 # copytree(src,dst) #拷贝文件夹里所有内容(递归拷贝) 28 shutil.copytree("ceshi777","ceshi666") 29 30 # rmtree(path) #删除当前文件夹及其中所有内容(递归删除) 31 shutil.rmtree("ceshi777") 32 33 # 5.剪切 34 # move(path1,paht2) #移动文件或者文件夹 35 shutil.move("ceshi1.txt","pycharm-community-2020.1.3/ceshi2.ttt")
1 def getallsize(pathvar): 2 size = 0 3 lst = os.listdir(pathvar) 4 for i in lst: 5 # 拼接成完整的绝对路径 6 pathnew = os.path.join(pathvar,i) 7 if os.path.isdir(pathnew): 8 # print("[文件夹]",i) 9 size += getallsize(pathnew) 10 elif os.path.isfile(pathnew): 11 # print("[文件]",i) 12 size += os.path.getsize(pathnew) 13 14 return size 15 16 res = getallsize(pathvar) 17 print(res)
9、tarfile 模块 后缀为.tar | .tar.gz | .tar.bz2
1 import tarfile 2 3 # ### 1.创建tar包 4 # 1.创建压缩包 5 tf = tarfile.open("ceshi1210.tar","w",encoding="utf-8") 6 # 2.写入文件 7 tf.add("/bin/cat","cat") 8 tf.add("/bin/chacl","chacl") 9 tf.add("/bin/cp","tmp/cp") 10 tf.add("/aaabbb","aaabbb") #可直接压缩文件夹 11 # 3.关闭文件 12 tf.close() # 225,280 13 14 # ### 2.创建.tar.gz包 15 tf = tarfile.open("ceshi1210.tar.gz","w:gz",encoding="utf-8") 16 tf.add("/bin/cat","cat") 17 tf.add("/bin/chacl","chacl") 18 tf.add("/bin/cp","tmp/cp") 19 tf.add("/aaabbb","aaabbb") 20 tf.close() # 96,797 21 22 # ### 3.创建.tar.bz2包 23 tf = tarfile.open("ceshi1210.tar.bz2","w:bz2",encoding="utf-8") 24 tf.add("/bin/cat","cat") 25 tf.add("/bin/chacl","chacl") 26 tf.add("/bin/cp","tmp/cp") 27 tf.add("/aaabbb","aaabbb") 28 tf.close() # 84078 29 30 # ### 解压文件 31 tf = tarfile.open("ceshi1210.tar.bz2","r",encoding="utf-8") 32 # 解压所有 33 # tf.extractall("ceshi1210") 34 # 解压单个(落脚在文件身上) 35 tf.extract("aaabbb/1.py","ceshi1210_1") 36 tf.close() 37 38 # ### 查看文件 (使用with语法) 39 with tarfile.open("ceshi1210.tar.bz2","r",encoding="utf-8") as tf: 40 lst = tf.getnames() 41 print(lst) 42 43 # ### 追加文件 44 """无法对已经压缩过的压缩包做内容的追加;""" 45 # with tarfile.open("ceshi1210.tar","a",encoding="utf-8") as tf: 46 # tf.add("/bin/mv","mv") # success 47 48 # with tarfile.open("ceshi1210.tar.bz2","a",encoding="utf-8") as tf: 49 # tf.add("/bin/mv","mv") # error 50 51 # ### 解决办法: 52 """ 53 1.先解压 54 2.将文件追加到该文件夹中 55 3.在重新过滤打包即可 56 """ 57 import shutil,os 58 pathvar = os.getcwd() 59 print(pathvar) # /mnt/hgfs/python33_gx/day17/代码 60 pathvar1 = os.path.join(pathvar,"ceshi1210.tar.bz2") # /mnt/hgfs/python33_gx/day17/代码/ceshi1210.tar.bz2 61 pathvar2 = os.path.join(pathvar,"ceshi1210_2") 62 63 64 # 1.先解压文件 65 with tarfile.open(pathvar1,"r",encoding="utf-8") as tf: 66 tf.extractall("ceshi1210_2") 67 68 # 2.将文件追加到该文件夹中 69 shutil.copy("/bin/nano",pathvar2) 70 71 # 3.在重新过滤打包即可 72 """过滤掉cat,剩下的数据打包""" 73 lst = os.listdir(pathvar2) 74 print(lst) # ['aaabbb', 'cat', 'chacl', 'nano', 'tmp'] 75 76 77 with tarfile.open(pathvar1,"w:bz2",encoding="utf-8") as tf: 78 for i in lst: 79 if i != "cat": 80 # 拼接好完整绝对路径 81 pathvar = os.path.join(pathvar2,i) 82 # 添加到压缩包中 83 tf.add(pathvar,i)
四、正则表达式
正则表达式由一些 [普通字符] 和一些 [元字符] 组成:
(1)普通字符包括大小写字母和数字
(2)元字符具有特殊含义,大体种类分为如下:
- .预定义字符集,字符组
- 量词
- 边界符
- 分组
语法: lst = re.findall("正则表达式","字符串")
1、匹配单个字符
1..预定义字符集
匹配内容 | |
---|---|
. | 匹配任意字符,除了换行符\n |
\d | 匹配数字 |
\D | 匹配非数字 |
\w | 匹配字母或数字或下划线 (正则函数中,支持中文的匹配) |
\W | 匹配非字母或数字或下划线 |
\s | 匹配任意的空白符 |
\S | 匹配任意非空白符 |
\n | 匹配一个换行符 |
\t | 匹配一个制表符 |
[] |
1 # \d 匹配数字 2 lst = re.findall("\d","kjsdkfj2134*&(&你胜多负少") 3 print(lst) 4 5 # \D 匹配非数字 6 lst = re.findall("\D","kjsdkfj2134*&(&你胜多负少") 7 print(lst) 8 9 # \w 匹配字母或数字或下划线 (正则函数中,支持中文的匹配) 10 lst = re.findall("\w","xboyww 1231 s撒旦法&*()J_H") 11 print(lst) 12 13 # \W 匹配非字母或数字或下划线 14 lst = re.findall("\W","xboyww 1231 s撒旦法&*()J_H") 15 print(lst) 16 17 # \s 匹配任意的空白符 (空格 \r \t \n ) 18 lst = re.findall('\s'," sdf jkjk \r ") 19 print(lst) 20 21 # \S 匹配任意非空白符 22 lst = re.findall('\S'," sdf jkjk \r ") 23 print(lst) 24 25 # \n 匹配一个换行符 26 strvar = """ 27 11122 28 """ 29 lst = re.findall(r"\n",strvar) 30 print(lst) 31 32 # \t 匹配一个制表符 33 strvar = """ 34 11122 3434 35 """ 36 lst = re.findall(r"\t",strvar) 37 print(lst)
2.字符组
说明 [默认必须从字符组中选一个] | |
---|---|
[...] | 匹配字符组中的字符 |
[^...] |
1 lst = re.findall("[123]","abc1def2zzz3") 2 print(lst) 3 4 print(re.findall('a[abc]b','aab abb acb adb')) # aab abb acb 5 6 print(re.findall('a[0123456789]b','a1b a2b a3b acb ayb')) # a1b a2b a3b 7 # 优化写法 0123456789 => 0-9 8 print(re.findall('a[0-9]b','a1b a2b a3b acb ayb')) # ['a1b', 'a2b', 'a3b'] 9 10 print(re.findall('a[abcdefg]b','a1b a2b a3b acb ayb adb')) # acb adb 11 # 优化写法 abcdefg => a-g 表达所有的小写字母 a-z 12 print(re.findall('a[a-g]b','a1b a2b a3b acb ayb adb')) 13 print(re.findall('a[a-z]b','a1b a2b a3b acb ayb adb')) # acb ayb adb 14 15 print(re.findall('a[ABCDEFG]b','a1b a2b a3b aAb aDb aYb')) # aAb aDb 16 # 优化写法 ABCDEFG => A-G 表达所有的大写字母 A-Z 17 print(re.findall('a[A-G]b','a1b a2b a3b aAb aDb aYb')) 18 print(re.findall('a[A-Z]b','a1b a2b a3b aAb aDb aYb')) # aAb aDb aYb 19 20 print(re.findall('a[0-9a-zA-Z]b','a-b aab aAb aWb aqba1b')) # aab aAb aWb aqb a1b 21 # 注意点 不能写0-z表达所有的字母+数字 会含有特殊字符 22 print(re.findall('a[0-z]b','a-b aab aAb aWb aqba1b a@b')) # aab aAb aWb aqb a1b a@b 23 24 print(re.findall('a[0-9][*#/]b','a1/b a2b a29b a56b a456b')) # a1/b 25 26 # ^ 在字符组当中,表达除了...的意思 , 27 print(re.findall('a[^-+*/]b',"a%b ccaa*bda&bd")) # a%b a&b
3.注意点
无论是正则表达式,还是后面字符串,前面写r一定不错
# 匹配 ^ - \ strvar = "a^c a-c a\c" lst = re.findall(r"a[\^\-\\]c",strvar) print(lst) print(lst[-1]) # \b 退格的意思(正则中还有边界符的含义 \b同时具有2层含义) lst = re.findall(r"a\\b",r"a\b") # print("a\b") print(lst)
2、多个字符匹配
1.量词
用法说明 | |
---|---|
? | 重复0次或1次 |
+ | 重复1次或多次 (至少1次) |
* | 重复0次或多次 (任意次) |
{n} | 重复n次 |
{n,} | 重复n次或更多次 (至少n次) |
{n,m} | 重复n到m次 |
.* .+ | 贪婪模式匹配 |
.*? .+? |
1 '''1) ? 匹配0个或者1个a ''' 2 print(re.findall('a?b','abbzab abb aab')) # ab b ab ab b ab 3 '''2) + 匹配1个或者多个a ''' 4 print(re.findall('a+b','b ab aaaaaab abb')) # ab aaaaaab ab 5 '''3) * 匹配0个或者多个a ''' 6 print(re.findall('a*b','b ab aaaaaab abbbbbbb')) # b ab aaaaaab ab b b b b b b 7 '''4) {m,n} 匹配m个至n个a ''' # 1 <= a <= 3 8 print(re.findall('a{1,3}b','aaab ab aab abbb aaz aabb')) # aaab ab aab ab aab 9 # a字符出现的次数是必须2次 10 print(re.findall('a{2}b','aaab ab aab abbb aaz aabb')) # aab aab aab 11 # a字符出现的次数至少2次 12 print(re.findall('a{2,}b','aaab ab aab abbb aaz aabb')) # aaab aab aab
2.贪婪匹配 与 非贪婪匹配 [语法:量词的后面加?号]
贪婪模式 : 默认向更多次匹配
回溯算法 : 从左向右一直匹配,直到匹配不到了,在回头,把上一次找到的元素返回;
非贪婪模式 : 默认向更少次匹配
1 strvar = "刘能和刘老根和刘一手111子222子" 2 lst = re.findall("刘.",strvar) # 刘能 刘老 刘一 3 print(lst) 4 5 lst = re.findall("刘.?",strvar) # 刘能 刘老 刘一 6 print(lst) 7 8 lst = re.findall("刘.+",strvar) # 刘能和刘老根和刘一手111子222子 9 print(lst) 10 11 lst = re.findall("刘.*",strvar) # 刘能和刘老根和刘一手111子222子 12 print(lst) 13 14 lst = re.findall("刘.{1,30}",strvar) # 刘能和刘老根和刘一手111子222子 15 print(lst) 16 17 lst = re.findall("刘.{1,30}子",strvar) # 刘能和刘老根和刘一手111子222子 18 print(lst)
1 lst = re.findall("刘.??",strvar) # ['刘', '刘', '刘'] 2 print(lst) 3 4 lst = re.findall("刘.+?",strvar) # 刘能 刘老 刘一 5 print(lst) 6 7 lst = re.findall("刘.*?",strvar) # ['刘', '刘', '刘'] 8 print(lst) 9 10 lst = re.findall("刘.{1,30}?",strvar) # 刘能 刘老 刘一 11 print(lst) 12 13 lst = re.findall("刘.{1,30}?子",strvar) # 刘能和刘老根和刘一手111子 14 print(lst)
3.边界符 \b
只要不是字母数字下划线都可以作为边界;
\b
(1) 转义字符 退格
(2) 正则中的边界符
- 卡住左边界: \bw
- 卡住右边界: d\b
# 卡住右边界 strvar = "word pwd book" lst = re.findall(r"d\b",strvar) lst = re.findall(r".*d\b",strvar) lst = re.findall(r".*?d\b",strvar) print(lst) # 卡住左边界 strvar = "pwd word book" lst = re.findall(r"\bw",strvar) # ['w'] lst = re.findall(r"\bw.*",strvar) # ['word pwd book'] lst = re.findall(r"\bw.*?",strvar) # ['w'] lst = re.findall(r"\bw.*? ",strvar) # ['w'] lst = re.findall(r"\bw\S*",strvar) # ["word"] print(lst)
4. ^ 匹配字符串的开始 $匹配字符串的结尾
如果使用了^ 和 $ 必须要把字符串看成一个整体
1 strvar = "大哥大嫂大爷" 2 print(re.findall('大.',strvar)) # ['大哥', '大嫂', '大爷'] 3 print(re.findall('^大.',strvar)) # 大哥 4 print(re.findall('大.$',strvar)) # 大爷 5 print(re.findall('^大.$',strvar)) # [] 6 print(re.findall('^大.*?$',strvar))# 大哥大嫂大爷 7 print(re.findall('^大.*?大$',strvar)) # [] 8 print(re.findall('^大.*?爷$',strvar)) # 大哥大嫂大爷 9 10 print(re.findall('^g.*? ' , 'giveme 1gfive gay')) #giveme 11 print(re.findall('five$' , 'aassfive')) # five 12 print(re.findall('^giveme$' , 'giveme')) # giveme 13 print(re.findall('^giveme$' , 'giveme giveme')) # [] 14 print(re.findall('giveme' , 'giveme giveme')) # giveme giveme 15 print(re.findall("^g.*e",'giveme 1gfive gay')) # giveme 1gfive
3、匹配分组 ()表达一个整体
1、匹配分组 ()
print(re.findall('.*?_good','wusir_good alex_good secret男_good'))#['wusir_good', ' alex_good', ' secret男_good'] # findall 会优先显示括号里面的内容 print(re.findall('(.*?)_good','wusir_good alex_good secret男_good'))#['wusir', ' alex', ' secret男'] # findall ?: 取消优先显示括号的功能 print(re.findall('(?:.*?)_good','wusir_good alex_good secret男_good'))#['wusir_good', ' alex_good', ' secret男_good']
2、|的使用
lst = re.findall("a|b","sdhfjha234234bkjkjk") print(lst) # ['a', 'b'] # 注意点: 把较难匹配的内容放到前面,容易匹配的内容放到后面,才能保证所有元素都能匹配到; lst = re.findall("abc|abcd","12342abcdjskdfjkabc") print(lst) # ["abc","abc"] lst = re.findall("abcd|abc","12342abcdjskdfjkabc") print(lst) # ['abcd', 'abc'
3、search
obj.group() => 获取匹配到的内容
obj.groups() => 获取分组中的内容
findall : 优点:从左到右匹配,找到所有的内容,返回到列表
缺点:匹配的内容和分组的内容不能同时显示在同一个界面中
search : 缺点:从左到右匹配,匹配到第一个满足条件的内容直接返回,最后返回的是对象
优点:可以把分组里的内容和匹配到的内容同时显示在同一个界面中
obj = re.search("(www)\.(baidu|oldboy)\.(com)",strvar) print(obj) # 获取匹配到的内容 res = obj.group() print(res) # 获取分组中的内容 # 方法一 (推荐) res = obj.groups() print(res) # 方法二 res = obj.group(1) print(res) res = obj.group(2) print(res) res = obj.group(3) print(res)
4、反向引用
# 把第一个括号里面的数据放到\1在引用一次; obj = re.search(r"<(.*?)>(.*?)<(/\1)>",strvar) print(obj) print(obj.group()) print(obj.groups()) strvar = "a1b2cab z4y5gzy" obj = re.search(r"(.*?)\d(.*?)\d(.*?)(\1)(\2)",strvar) print(obj.group()) # a1b2cab print(obj.groups())
5、命名分组
?P<组名>正则表达式) 给这个组起一个名字
(?P=组名) 引用之前组的名字,把该组名匹配到的内容放到当前位置
# 方法一 obj = re.search(r"(?P<tag1>.*?)\d(?P<tag2>.*?)\d(?P<tag3>.*?)(\1)(\2)",strvar) print(obj) print(obj.group()) print(obj.groups()) # 方式二 obj = re.search(r"(?P<tag1>.*?)\d(?P<tag2>.*?)\d(?P<tag3>.*?)(?P=tag1)(?P=tag2)",strvar) print(obj) print(obj.group()) print(obj.groups())
6、正则函数
1.search
通过正则匹配出第一个对象返回,通过group取出对象中的值 ,通过groups取出分组当中的数据
2.match
search 和 match 使用时一模一样,区别在于在search正则表达式的开头加上^ 等价于 match
3.split 切割
strvar = "alex2674623wusir22xboyww55555risky" res = re.split("\d+",strvar) print(res)
4.sub 替换
sub(正则表达式,替换的元素,替换的原字符串[,替换的次数])
strvar = "alex_wusir|xboyww&risky" res = re.sub("[_|&]","@",strvar,2) print(res)
subn 替换
subn 对比 sub 只是在返回值有所不同,返回的是元组(字符串,替换次数)
strvar = "alex_wusir|xboyww&risky" res = re.subn("[_|&]","@",strvar) print(res) # ('alex@wusir@xboyww@risky', 3)
5、finditer 匹配字符串中相应内容,返回迭代器
from collections import Iterator,Iterable strvar = "sdf234sdfjkhj&^&*^987" it = re.finditer("\d",strvar) print(isinstance(it,Iterator)) for i in it: # print(i) print(i.group())
6、compile 指定一个统一的匹配规则
可以制定一次正则表达式,编译一次,终身受益,不需要反复编译,提升执行效率
pattern = re.compile("\d") print(pattern) strvar = "sdf234sdfjkhj&^&*^987" # search的使用 obj = pattern.search(strvar) print(obj.group()) # findall的使用 res = pattern.findall(strvar) print(res
7、修饰符
说明 | |
---|---|
re.I | 使匹配对大小写不敏感 |
re.M | 使每一行都能够单独匹配(多行匹配),影响 ^ 和 $ |
re.S |
1 # (1) re.I 使匹配对大小写不敏感 2 strvar = "<h1>我是大标题</h1>" 3 pattern = re.compile("<h1>(.*?)</H1>" , flags = re.I) 4 obj = pattern.search(strvar) 5 print(obj) 6 print(obj.group()) 7 print(obj.groups()) 8 9 # (2) re.M 使每一行都能够单独匹配(多行匹配),影响 ^ 和 $ 10 strvar = """ 11 <a>我是连接</a> 12 <p>我是段落</p> 13 <div>我是盒子</div> 14 """ 15 16 pattern = re.compile("^<.*?>.*?<.*?>$",flags = re.M) 17 lst = pattern.findall(strvar) 18 print(lst) 19 # print(obj) 20 # print(obj.group()) 21 22 23 # (3) re.S 使 . 匹配包括换行在内的所有字符 24 strvar = """ 25 please give 26 234234mefive 27 """ 28 pattern = re.compile(".*?mefive" , flags=re.S) 29 obj = pattern.search(strvar) 30 print(obj) 31 print(obj.group()) # 234234mefive
(扩展) 如果想要所有的修饰符 使用 | 进行拼接
pattern = re.compile(".*?mefive" , flags=re.S|re.M|re.I) obj = pattern.search(strvar) print(obj)