1. 程式人生 > 實用技巧 >我的python學習之路-基礎4

我的python學習之路-基礎4

本節內容:

  1. 遞迴函式
  2. 內建函式
  3. 模組
  4. 正則表示式

一、 遞迴函式

定義:自己呼叫自己的函式,就是遞迴函式

  遞:去 歸:回 一去一回是遞迴

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 '''
View Code

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 """
View Code

尾遞迴在一些特別的直譯器中,每次呼叫函式時,都只在記憶體中開闢一個棧幀空間,

後者替換前者,只要最後一層空間有資料返回,直接結束.
但是目前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)
View Code

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
View Code

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))
View Code
(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))
View Code

一次性把所有資料全部拿取出來

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))
View Code

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")
View Code
 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))
os模組操作
 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")
os模組具有 新建/刪除
 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)
os.path

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")
View Code

 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)
View Code

四、正則表示式

正則表示式由一些 [普通字元] 和一些 [元字元] 組成:
(1)普通字元包括大小寫字母和數字
(2)元字元具有特殊含義,大體種類分為如下:

  1. .預定義字符集,字元組
  2. 量詞
  3. 邊界符
  4. 分組

語法: 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)
View Code

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
View Code

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
View Code

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) 正則中的邊界符

  1. 卡住左邊界: \bw
  2. 卡住右邊界: 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
View Code

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
View Code

(擴充套件) 如果想要所有的修飾符 使用 | 進行拼接

pattern = re.compile(".*?mefive" , flags=re.S|re.M|re.I)
obj = pattern.search(strvar)
print(obj)