一、生成器的語句形式html
a.生成器相關python函數、裝飾器、迭代器、生成器,咱們是如何使用生成器的。一個生成器能暫停執行並返回一箇中間的結果這就是 yield 語句的功能 : 返回一箇中間值給調用者並暫停執行。python
咱們的調用方式爲yeild 1的方式,此方式又稱爲生成器的語句形式。mysql
而使用生成器的場景:使用生成器最好的場景就是當你須要以迭代的方式去穿越一個巨大的數據集合。好比:一個巨大的文件/一個複雜的數據庫查詢等。linux
1 # def read_file(fpath): 2 # BLOCK_SIZE = 1024 3 # with open(fpath, 'rb') as f: 4 # while True: 5 # block = f.read(BLOCK_SIZE) 6 # if block: 7 # yield block 8 # else: 9 # return 10 11 ''' 12 結果: 13 以上傳入參數就能夠按1024字符,以迭代的方式,返回讀取內容,內存只佔1024字符 14 '''
b.增強的生成器特性:git
除了可使用 next() 方法來獲取下一個生成的值,用戶還可使用 send() 方法將一個新的或者是被修改的值返回給生成器。除此以外,還可使用 close() 方法來隨時退出生成器。正則表達式
1 ''' 2 b.增強的生成器特性 3 除了可使用 next() 方法來獲取下一個生成的值,用戶還可使用 send() 方法將一個新 4 的或者是被修改的值返回給生成器。除此以外,還可使用 close() 方法來隨時退出生成器。 5 ''' 6 # def eater(name): 7 # print('%s ready to eat!!!' % (name)) 8 # count = 1 9 # while True: 10 # yield count 11 # count += 1 12 # print('%s eating' % (name)) 13 # 14 # g = eater('Tom') 15 # print(next(g)) 16 # print(next(g)) 17 ''' 18 直接運行g.send()報錯,爲生成器沒有初始化,因此使用.send(),第一個值必須初始化 19 Traceback (most recent call last): 20 File "D:/old_boy/old_boy_17_05/yield_ex1.py", line 66, in <module> 21 print(g.send('shuyang')) 22 TypeError: can't send non-None value to a just-started generator 23 # print(g.send('shuyang')) 24 ''' 25 # print(g.send(None)) # .send(None) == next(g) 26 # print(g.send(None)) 27 # g.close() # 退出生成器 28 # next(g) 29 ''' 30 結果: 31 Tom ready to eat!!! 32 1 33 Tom eating 34 2 35 Tom eating 36 3 37 Tom eating 38 4 39 Traceback (most recent call last): 40 File "D:/old_boy/old_boy_17_05/yield_ex1.py", line 62, in <module> 41 next(g) 42 StopIteration 43 '''
直接運行g.send()會報錯,爲生成器沒有初始化,因此使用.send(),第一次必須使用.send(None)初始化生成器算法
二、生成器的表達式形式sql
a.簡單用法,其實x = yield,就是一個表達式,yield不只僅是一個語句,它還能夠用.send()特性,作賦值操做。數據庫
1 # # 裝飾器,執行生成器第一次初始化 2 # def deco(func): 3 # def wrapper(*args,**kwargs): 4 # res=func(*args,**kwargs) 5 # next(res) 6 # return res 7 # return wrapper 8 # 9 # @deco 10 # def eater(name): 11 # print('%s ready to eat!!!' % name) 12 # while True: 13 # food = yield 14 # print('%s eating %s' % (name, food)) 15 # 16 # g = eater('alex11') 17 # # next(g) # g.send(None) 18 # g.send('麪條') 19 # g.send('饅頭') 20 # g.send('包子') 21 22 ''' 23 結果: 24 alex11 ready to eat!!! 25 alex11 eating 麪條 26 alex11 eating 饅頭 27 alex11 eating 包子 28 '''
b.經過生成式表達式優化列表解析:二者的語法很是類似,但生成器表達式返回的不是一個列表類型對象,而是一個生成器對象,生成器是一個內存使用友好的結構。編程
列表解析:
[expr for iter_var in iterable if cond_expr]
生成器表達式:
(expr for iter_var in iterable if cond_expr)
1 # 列表寫法 2 l = ['egg%s' %i for i in range(10)] 3 print(l) 4 # 生成器寫法 5 g = ('egg%s' %i for i in range(10)) 6 # print(g) 7 # print(next(g)) 8 # print(next(g)) 9 # for i in g: 10 # print(i) 11 print(list(g)) 12 ''' 13 結果: 14 ['egg0', 'egg1', 'egg2', 'egg3', 'egg4', 'egg5', 'egg6', 'egg7', 'egg8', 'egg9'] 15 ['egg0', 'egg1', 'egg2', 'egg3', 'egg4', 'egg5', 'egg6', 'egg7', 'egg8', 'egg9'] 16 '''
1 # 文件寫法 2 # 列表存值寫法 3 # f = open('FILENAME', 'r') 4 # allLinesLen = [line(x.strip()) for x in f] 5 # f.close() 6 # return max(allLinesLen) # 返回列表中最大的數值 7 # 生成器存值寫法 8 # f = open('FILENAME', 'r') 9 # allLinesLen = (line(x.strip()) for x in f) # 這裏的 x 至關於 yield x 10 # f.close() 11 # return max(allLinesLen)
三、協程函數
在python中,協程函數就是使用了yield表達式形式的生成器。
它的優勢爲省內存,沒有鎖的概念、利用if判斷,執行效率高。此概念主要應用在用戶態線程中。
1 ''' 2 3、協程函數 3 協程函數就是使用了yield表達式形式的生成器 4 ''' 5 def deco(func): 6 def warrper(*args, **kwargs): 7 res = func(*args, **kwargs) 8 res.send(None) # 初始化生成器 9 return res 10 return warrper 11 12 @deco 13 def eater(name): 14 print('%s ready to eat!!!' % name) 15 food_list = [] 16 while True: 17 food = yield food_list 18 # 因yield,程序在這裏停頓,因此,要添加yield返回值操做,必須在yield後 19 food_list.append(food) 20 print('%s eating %s' % (name, food)) 21 22 g = eater('alex') 23 #next(g) # g.send(None) 24 print(g.send('麪條')) 25 print(g.send('饅頭')) 26 print(g.send('包子')) 27 28 ''' 29 結果: 30 alex ready to eat!!! 31 alex eating 麪條 32 ['麪條'] 33 alex eating 饅頭 34 ['麪條', '饅頭'] 35 alex eating 包子 36 ['麪條', '饅頭', '包子'] 37 '''
ps.協程的概念:
爲了進一步減少內核態線程上下文切換的開銷,因而又有了用戶態線程設計,即纖程(Fiber)。若是連時鐘阻塞、 線程切換這些功能咱們都不須要了,本身在進程裏面寫一個邏輯流調度的東西。那麼咱們便可以利用到併發優點,又能夠避免反覆系統調用,還有進程切換形成的開銷,分分鐘給你上幾千個邏輯流不費力。這就是用戶態線程。
四、協程函數示例:仿grep -rl ‘python’ /root
1 #!/usr/bin/env python 2 # -*- coding:utf-8 -*- 3 4 ''' 5 yield的應用場景 6 grep -rl 'python' /root 7 ''' 8 import os 9 10 def init(func): 11 def wrapper(*args, **kwargs): 12 res = func(*args, **kwargs) 13 next(res) 14 return res 15 return wrapper 16 17 # 第一個@init必須寫,不然生成器沒法完成所有代碼的初始化 18 @init 19 def search(target): 20 ''' 21 拼接字符串 22 :param target: 生成器內存地址 23 :return: 24 ''' 25 while True: 26 search_path = yield 27 # os.walk() 方法用於經過在目錄樹種遊走輸出在目錄中的文件名,向上或者向下 28 # 結果:('a', ['b'], ['a.txt', '__init__.py'])(目錄名,子目錄,文件) 29 g = os.walk(search_path) 30 for par_dir, _, files in g: 31 for file in files: 32 # r''爲原生字符串,不通過python解釋器編譯(windows下路徑表示尤其有用) 33 file_abs_path = r'%s\%s' %(par_dir, file) 34 # print(file_abs_path) 35 # 下一層生成器 36 target.send(file_abs_path) 37 @init 38 def opener(target): 39 ''' 40 打開文件 41 :param target: 生成器內存地址 42 :return: 查看文件內容生成器發送文件地址,文件句柄 43 ''' 44 while True: 45 file_abs_path = yield # 接收search傳遞的路徑 46 with open(file_abs_path, encoding='utf-8') as f: 47 #print(f) 48 target.send((file_abs_path, f)) # send多個用元組的方式,爲了把文件的路徑傳遞下去 49 50 # g = search(opener()) 51 # g.send('a') 52 ''' 53 結果: 54 <_io.TextIOWrapper name='a/a.txt' mode='r' encoding='utf-8'> 55 <_io.TextIOWrapper name='a/__init__.py' mode='r' encoding='utf-8'> 56 <_io.TextIOWrapper name='a\\b/b.txt' mode='r' encoding='utf-8'> 57 <_io.TextIOWrapper name='a\\b/__init__.py' mode='r' encoding='utf-8'> 58 <_io.TextIOWrapper name='a\\b\\c/c.txt' mode='r' encoding='utf-8'> 59 <_io.TextIOWrapper name='a\\b\\c/__init__.py' mode='r' encoding='utf-8'> 60 <_io.TextIOWrapper name='a\\b\\c\\d/d.txt' mode='r' encoding='utf-8'> 61 <_io.TextIOWrapper name='a\\b\\c\\d/__init__.py' mode='r' encoding='utf-8'> 62 ''' 63 64 @init 65 def cat(target): 66 ''' 67 查看文件內容 68 :param target: 生成器內存地址 69 :return: 查找匹配line生成器,文件地址和一行內容 70 ''' 71 while True: 72 file_abs_path, f = yield 73 for line in f: 74 tag = target.send((file_abs_path, line)) 75 # 優化函數,文件找到關鍵字則返回文件,tag爲此標記 76 if tag: 77 break 78 79 @init 80 def grep(target, pattern): 81 ''' 82 查找匹配line 83 :param target: 生成器內存地址 84 :param pattern: 查詢的關鍵字 85 :return: 打印行生成器,發送文件地址 86 ''' 87 # 優化函數,文件找到關鍵字則返回文件,tag爲此標記 88 tag = False 89 while True: 90 file_abs_path, line = yield tag 91 # tag此標記,初始化寫在yield以後 92 tag = False 93 if pattern in line: 94 tag = True 95 target.send(file_abs_path) 96 97 @init 98 def printer(): 99 ''' 100 打印行 101 :return: 102 ''' 103 while True: 104 file_abs_path = yield 105 print(file_abs_path) 106 107 108 x = r'D:\old_boy\old_boy_17_05\a' 109 g = search(opener(cat(grep(printer(),'python')))) 110 print(g) 111 g.send(x) 112 113 ''' 114 結果: 115 <generator object search at 0x0000004FFDCCB780> 116 D:\old_boy\old_boy_17_05\a\a.txt 117 D:\old_boy\old_boy_17_05\a\__init__.py 118 D:\old_boy\old_boy_17_05\a\b\b.txt 119 D:\old_boy\old_boy_17_05\a\b\__init__.py 120 D:\old_boy\old_boy_17_05\a\b\c\__init__.py 121 D:\old_boy\old_boy_17_05\a\b\c\d\d.txt 122 D:\old_boy\old_boy_17_05\a\b\c\d\__init__.py 123 '''
ps.
a.有yield的函數,必須@init初始化(next(<g>))
b.這種寫法,必須層層嵌套調用,不能漏下任何一行。
c. a目錄結構:
是一種流水線式的編程思路,是機械式。以上grep -rl 'python' /root實例就是一個典型的面向過程編程。
一、優勢:
程序的結構清晰,能夠把複雜的問題簡單
二、缺點:
擴展性差
三、應用場景:
linux內核,git,httpd
ps.本節只是淺淺的討論一下,後續會有詳細分析。
遞歸算法是一種直接或者間接地調用自身算法的過程。在計算機編寫程序中,遞歸算法對解決一大類問題是十分有效的,它每每使算法的描述簡潔並且易於理解。
a.特色:
遞歸算法解決問題的特色:
ps.因此通常不提倡用遞歸算法設計程序。
b.要求:
遞歸算法所體現的「重複」通常有三個要求:
方式一:在函數調用自身
1 # 書寫方式1: 2 def f1(): 3 print('from f1') 4 f1() 5 f1() 6 ''' 7 結果: 8 from f1 9 from f1 10 from f1 11 from f1 f1() 12 File "D:/old_boy/old_boy_17_05/遞歸調用.py", line 32, in f1 13 f1() 14 [Previous line repeated 993 more times] 15 File "D:/old_boy/old_boy_17_05/遞歸調用.py", line 31, in f1 16 print('from f1') 17 RecursionError: maximum recursion depth exceeded while calling a Python object 18 遞歸超過文件最大限制 19 '''
方式二:在過程裏調用自身
1 # 書寫方式2: 2 def f1(): 3 print('f1') 4 f2() 5 6 def f2(): 7 print('f2') 8 f1() 9 10 f1() 11 ''' 12 結果: 13 f1 14 f2 15 f1 16 f2 17 f1 18 f2 19 f1 20 f2 21 RecursionError: maximum recursion depth exceeded while calling a Python object 22 遞歸超過文件最大限制 23 '''
一、簡單的遞歸示例
import sys # 查看當前遞歸最大值,默認爲1000 print(sys.getrecursionlimit()) # 修改當前遞歸最大值 print(sys.setrecursionlimit(1000000)) print(sys.getrecursionlimit()) ''' 結果: 1000 None 1000000 '''
二、遞歸應用之二分法
#遞歸應用之二分法:
1 #遞歸應用之二分法: 2 # l = range(0,400000) 3 l = [1, 2, 10,33,53,71,73,75,77,85,101,201,202,999,11111] 4 5 def search(find_num,seq): 6 if len(seq) == 0: 7 print('not exists') 8 return 9 mid_index=len(seq)//2 10 mid_num=seq[mid_index] 11 print(seq,mid_num) 12 if find_num > mid_num: 13 #in the right 14 seq=seq[mid_index+1:] 15 search(find_num,seq) 16 elif find_num < mid_num: 17 #in the left 18 seq=seq[:mid_index] 19 search(find_num,seq) 20 else: 21 print('find it') 22 23 search(77,l) 24 ''' 25 結果: 26 [1, 2, 10, 33, 53, 71, 73, 75, 77, 85, 101, 201, 202, 999, 11111] 75 27 [77, 85, 101, 201, 202, 999, 11111] 201 28 [77, 85, 101] 85 29 [77] 77 30 find it 31 ''' 32 # search(72,l) 33 ''' 34 結果: 35 [1, 2, 10, 33, 53, 71, 73, 75, 77, 85, 101, 201, 202, 999, 11111] 75 36 [1, 2, 10, 33, 53, 71, 73] 33 37 [53, 71, 73] 71 38 [73] 73 39 not exists 40 '''
三、尾遞歸優化
待補全
匿名函數就是不須要顯式的指定函數,python中使用lambda 函數是一種快速定義單行的最小函數,能夠用在任何須要函數的地方。
配合一些內置函數的使用,能夠更增強大,但依舊爲簡單的函數:
支持lambda的內置函數以下:
max、min、zip、sorted
map、reduce、filter
匿名函數優勢:
a. 程序一次行使用,因此不須要定義函數名,節省內存中變量定義空間
b. 若是想讓程序更加簡潔時。
一、常規使用
1 # 正常函數 2 def func(x,y): 3 return x+y 4 print(func(1,2)) 5 ''' 6 結果: 7 3 8 ''' 9 10 11 # 匿名函數 12 f=lambda x,y:x+y 13 print(f) 14 print(f(1,2)) 15 ''' 16 結果: 17 <function <lambda> at 0x0000001C641BC8C8> 18 3 19 '''
、max、min、zip、sort結合應用
max max(sequence,key=<lambda 值:表達式>==func) 最大值
min min(sequence,key=<lambda 值:表達式>==func) 最小值
zip zip(sequence,sequence) 兩個sequence的len()值必須相等,拉鍊函數,字典
sorted sorted(可迭代對象,key=<lambda 值:表達式>==func,reverse=True ) 排序函數,默認從小到大,reverse反轉
1 #max,min,zip,sorted的用法 2 # 字典的運算:最小值,最大值,排序方法一: 3 # salaries={ 4 # 'egon':3000, 5 # 'alex':100000000, 6 # 'wupeiqi':10000, 7 # 'yuanhao':2000 8 # } 9 # 迭代字典,key值,默認的key值是不對的 10 salaries={ 11 'egon':3000, 12 'alex':100000000, 13 'wupeiqi':10000, 14 'yuanhao':2000 15 } 16 # print(max(salaries)) 17 ''' 18 結果: 19 yuanhao 20 ''' 21 # print(min(salaries)) 22 ''' 23 結果: 24 alex 25 ''' 26 27 # 迭代字典,取得指定key,於是比較的是key的最大和最小值 28 salaries={ 29 'egon':3000, 30 'alex':100000000, 31 'wupeiqi':10000, 32 'yuanhao':2000 33 } 34 # print(max(salaries,key=lambda k:salaries[k])) 35 ''' 36 結果: 37 alex 38 ''' 39 # print(min(salaries,key=lambda k:salaries[k])) 40 ''' 41 結果: 42 yuanhao 43 ''' 44 45 # 也能夠經過zip的方式實現 46 # salaries={ 47 # 'egon':3000, 48 # 'alex':100000000, 49 # 'wupeiqi':10000, 50 # 'yuanhao':2000 51 # } 52 # res=zip(salaries.values(),salaries.keys()) 53 # # print(list(res)) 54 # print(max(res)) 55 ''' 56 結果: 57 (100000000, 'alex') 58 ''' 59 60 # 至關於 61 # salaries={ 62 # 'egon':3000, 63 # 'alex':100000000, 64 # 'wupeiqi':10000, 65 # 'yuanhao':2000 66 # } 67 # def func(k): 68 # return salaries[k] 69 70 # print(max(salaries,key=func)) 71 72 # sorted排序 73 # salaries={ 74 # 'egon':3000, 75 # 'alex':100000000, 76 # 'wupeiqi':10000, 77 # 'yuanhao':2000 78 # } 79 # print(sorted(salaries)) #默認的排序結果是從小到大 80 # print(sorted(salaries,key=lambda x:salaries[x])) #默認的金錢排序結果是從小到大 81 # print(sorted(salaries,key=lambda x:salaries[x],reverse=True)) #默認的金錢排序結果是從大到小 82 ''' 83 結果: 84 ['alex', 'egon', 'wupeiqi', 'yuanhao'] 85 ['yuanhao', 'egon', 'wupeiqi', 'alex'] 86 ['alex', 'wupeiqi', 'egon', 'yuanhao'] 87 '''
、map、reduce、filter結合應用
a.map map(function, sequence[, sequence, ...]) -> list
對sequence中的item依次執行function(item),執行結果輸出爲list。
>>> map(str, range(5)) #對range(5)各項進行str操做 ['0', '1', '2', '3', '4'] #返回列表 >>> def add(n):return n+n ... >>> map(add, range(5)) #對range(5)各項進行add操做 [0, 2, 4, 6, 8] >>> map(lambda x:x+x,range(5)) #lambda 函數,各項+自己 [0, 2, 4, 6, 8] >>> map(lambda x:x+1,range(10)) #lambda 函數,各項+1 [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] >>> map(add,'zhoujy') ['zz', 'hh', 'oo', 'uu', 'jj', 'yy'] #想要輸入多個序列,須要支持多個參數的函數,注意的是各序列的長度必須同樣,不然報錯: >>> def add(x,y):return x+y ... >>> map(add,'zhoujy','Python') ['zP', 'hy', 'ot', 'uh', 'jo', 'yn'] >>> def add(x,y,z):return x+y+z ... >>> map(add,'zhoujy','Python','test') #'test'的長度比其餘2個小 Traceback (most recent call last): File "<stdin>", line 1, in <module> TypeError: add() takes exactly 2 arguments (3 given) >>> map(add,'zhoujy','Python','testop') ['zPt', 'hye', 'ots', 'uht', 'joo', 'ynp']
b.reduce reduce(function, sequence[, initial]) -> value
對sequence中的item順序迭代調用function,函數必需要有2個參數。要是有第3個參數,則表示初始值,能夠繼續調用初始值,返回一個值。
python3中,須要python3中須要from functools import reduce才能調用
1 >>> def add(x,y):return x+y 2 ... 3 >>> reduce(add,range(10)) #1+2+3+...+9 4 45 5 >>> reduce(add,range(11)) #1+2+3+...+10 6 55 7 >>> reduce(lambda x,y:x*y,range(1,3),5) #lambda 函數,5是初始值, 1*2*5 8 10 9 >>> reduce(lambda x,y:x*y,range(1,6)) #階乘,1*2*3*4*5 10 120 11 >>> reduce(lambda x,y:x*y,range(1,6),3) #初始值3,結果再*3 12 360 13 >>> reduce(lambda x,y:x+y,[1,2,3,4,5,6]) #1+2+3+4+5+6 14 21
c.filter filter(function or None, sequence) -> list, tuple, or string
對sequence中的item依次執行function(item),將執行結果爲True(!=0)的item組成一個List/String/Tuple(取決於sequence的類型)返回,False則退出(0),進行過濾。
1 >>> def div(n):return n%2 2 ... 3 >>> filter(div,range(5)) #返回div輸出的不等於0的真值 4 [1, 3] 5 >>> filter(div,range(10)) 6 [1, 3, 5, 7, 9] 7 >>> filter(lambda x : x%2,range(10)) #lambda 函數返回奇數,返回列表 8 [1, 3, 5, 7, 9] 9 >>> filter(lambda x : not x%2,range(10)) 10 [0, 2, 4, 6, 8] 11 >>> def fin(n):return n!='z' #過濾'z' 函數,出現z則返回False 12 ... 13 >>> filter(fin,'zhoujy') #'z'被過濾 14 'houjy' 15 >>> filter(lambda x : x !='z','zhoujy') #labmda返回True值 16 'houjy' 17 >>> filter(lambda x : not x=='z','zhoujy') #返回:字符串 18 'houjy'
d.map、reduce、filter應用示例:
實現5!+4!+3!+2!+1!
1 #!/usr/bin/env python 2 #-*- coding:utf-8 -*- 3 def add_factorial(n): 4 empty_list=[] #聲明一個空列表,存各個階乘的結果,方便這些結果相加 5 for i in map(lambda x:x+1,range(n)): #用傳進來的變量(n)來生成一個列表,用map讓列表都+1,eg:range(5) => [1,2,3,4,5] 6 a=reduce(lambda x,y:x*y,map(lambda x:x+1,range(i))) #生成階乘,用map去掉列表中的0 7 empty_list.append(a) #把階乘結果append到空的列表中 8 return empty_list 9 if __name__ == '__main__': 10 import sys 11 #2選1 12 #(一) 13 try: 14 n = input("Enter a Number(int) : ") 15 result=add_factorial(n) #傳入變量 16 print reduce(lambda x,y:x+y,result) #階乘結果相加 17 except (NameError,TypeError): 18 print "That's not a Number!" 19 #(二) 20 # result = add_factorial(int(sys.argv[1])) #傳入變量 21 # print reduce(lambda x,y:x+y,result) #階乘結果相加
將100~200之內的質數挑選出來
1 ''' 2 思路: 3 4 質數是指:只有1和它自己兩個因數,如二、3、5、7都是質數,即能被1和自己整除,1不是質數。 5 好比一個數字N,看它是否質數的話,就要看:有沒有能整除【2,N】之間的數X(不包含自己),即N%X是否爲0,要是沒有就爲質數。 6 因此咱們要實現的算法是:拿一個數字N,去除以【2,N】之間的數X,來獲得質數,即:N/2,N/3,……,N/N-2,N/N-1 ===> N/range(2,N) 7 ''' 8 #!/usr/bin/env python 9 #-*- coding:utf-8 -*- 10 def is_prime(start,stop): 11 stop = stop+1 #包含列表右邊的值 12 prime = filter(lambda x : not [x%i for i in range(2,x) if x%i == 0],range(start,stop)) #取出質數,x從range(start,stop) 取的數 13 print prime 14 15 if __name__ == '__main__': 16 try : 17 start = input("Enter a start Number :") 18 except : 19 start = 2 #開始值默認2 20 try : 21 stop = input("Enter a stop Number :") 22 except : 23 stop = 0 #中止數,默認0,即不返回任何值 24 is_prime(start,stop) 25 ''' 26 結果: 27 Enter a start Number :10 28 Enter a stop Number :20 29 [11, 13, 17, 19] 30 '''
一個模塊就是一個包含了python定義和聲明的文件,文件名就是模塊名字加上.py的後綴。
a.爲什麼要使用模塊?
若是你退出python解釋器而後從新進入,那麼你以前定義的函數或者變量都將丟失,所以咱們一般將程序寫到文件中以便永久保存下來,須要時就經過python test.py方式去執行,此時test.py被稱爲腳本script。
隨着程序的發展,功能愈來愈多,爲了方便管理,咱們一般將程序分紅一個個的文件,這樣作程序的結構更清晰,方便管理。這時咱們不只僅能夠把這些文件當作腳本去執行,還能夠把他們當作模塊來導入到其餘的模塊中,實現了功能的重複利用。
b.模塊的搜索順序:
c.模塊分爲三種:
ps.須要特別注意的是:咱們自定義的模塊名不該該與系統內置模塊重名
一、導入模塊:
示例文件spam.py(執行文件同級目錄)
1 print('from the spam.py') 2 money = 1000 3 4 def read1(): 5 print('spam->read1->money', money) 6 7 def read2(): 8 print('spam->read2->calling read1') 9 read1() 10 11 def change(): 12 global money 13 money = 0
a.模塊能夠包含可執行的語句和函數的定義,這些語句的目的是初始化模塊,它們只在模塊名第一次遇到導入import語句時才執行.(python的內存優化手段)
b.每一個模塊都是一個獨立的名稱空間,定義在這個模塊中的函數,把這個模塊的名稱空間當作全局名稱空間,這樣咱們在編寫本身的模塊時,就不用擔憂咱們定義在本身模塊中全局變量會在被導入時,與使用者的全局變量衝突.
1 # 只在第一次導入時才執行spam.py內代碼,此處的顯式效果是隻打印一次'from the spam.py',固然其餘的頂級代碼也都被執行了,只不過沒有顯示效果. 2 # import spam_mod 3 # import spam_mod 4 # import spam_mod 5 # import spam_mod 6 ''' 7 結果: 8 from the spam_moy.py 9 ''' 10 11 #測試一:money與spam.money不衝突 12 # import spam_mod 13 # money=10 14 # print(spam_mod.money) 15 ''' 16 結果: 17 from the spam_mod.py 18 1000 19 ''' 20 21 # 測試二:read1與spam.read1不衝突 22 # import spam_mod 23 # def read1(): 24 # print('========') 25 # spam_mod.read1() 26 ''' 27 結果: 28 from the spam_mod.py 29 spam_mod->read1->money 1000 30 ''' 31 32 # 測試三:執行spam.change()操做的全局變量money仍然是spam中的 33 # import spam_mod 34 # money=1 35 # spam_mod.change() 36 # print(money) 37 38 ''' 39 執行結果: 40 from the spam_mod.py 41 1 42 '''
ps.import導入時所作的事情:
1.產生新的名稱空間
2.以新建的名稱空間爲全局名稱空間,執行文件的代碼
3.拿到一個模塊名spam,指向spam.py產生的名稱空間
對比import spam,會將源文件的名稱空間'spam'帶到當前名稱空間中,使用時必須是spam.名字的方式而from 語句至關於import,也會建立新的名稱空間,可是將spam中的名字直接導入到當前的名稱空間中,在當前名稱空間中,直接使用名字就能夠了.
對比import:
優勢:方便,不用加前綴
缺點:容易跟當前文件的名稱空間衝突
1 # from spam import read1,read2 2 3 # 測試一:導入的函數read1,執行時仍然回到spam.py中尋找全局變量money 4 # from spam_mod import read1 5 # money=1000 6 # read1() 7 ''' 8 執行結果: 9 from the spam.py 10 spam_mod->read1->money 1000 11 ''' 12 13 #測試二:導入的函數read2,執行時須要調用read1(),仍然回到spam.py中找read1() 14 # from spam_mod import read2 15 # def read1(): 16 # print('==========') 17 # read2() 18 19 ''' 20 執行結果: 21 from the spam.py 22 spam_mod->read2->calling read1 23 spam_mod->read1->money 1000 24 ''' 25 26 # 測試三:導入的函數read1,被當前位置定義的read1覆蓋掉了 27 # from spam_mod import read1 28 # def read1(): 29 # print('==========') 30 # read1() 31 ''' 32 執行結果: 33 from the spam.py 34 ========== 35 '''
-加as,別名寫法:
from spam_mod import read1 as read
-多行寫法:
from spam import (read1,
read2,
money)
-*寫法:from spam import *, 把spam中全部的不是如下劃線(_)開頭的名字都導入到當前位置
1 # from spam import * 2 from spam_mod import * #將模塊spam中全部的名字都導入到當前名稱空間 3 print(money) 4 print(read1) 5 print(read2) 6 print(change) 7 8 ''' 9 執行結果: 10 from the spam_mod.py 11 1000 12 <function read1 at 0x1012e8158> 13 <function read2 at 0x1012e81e0> 14 <function change at 0x1012e8268> 15 '''
ps.form ... import ...導入時所作的事情:
1.產生新的名稱空間
2.以新建的名稱空間爲全局名稱空間,執行文件的代碼
3.直接拿到就是spam.py產生的名稱空間中名字
二、__all__變量與__name__變量
1 from spam_mod import * 2 print(money) # 加入的能夠執行 3 read1() # 沒有加入__all__的執行報錯 4 5 ''' 6 結果: 7 from the spam_mod.py 8 1000 9 Traceback (most recent call last): 10 File "D:/old_boy/old_boy_17_05/模塊/mod_py.py", line 167, in <module> 11 read1() 12 NameError: name 'read1' is not defined 13 '''
ps.使用 importlib.reload(), e.g. import importlib; 能夠重載被倒入的模塊,這隻能用於測試環境。
ps.做用:用來控制.py文件在不一樣的應用場景下執行不一樣的邏輯
1 def fib(n): # write Fibonacci series up to n 2 a, b = 0, 1 3 while b < n: 4 print(b, end=' ') 5 a, b = b, a+b 6 print() 7 8 def fib2(n): # return Fibonacci series up to n 9 result = [] 10 a, b = 0, 1 11 while b < n: 12 result.append(b) 13 a, b = b, a+b 14 return result 15 16 if __name__ == "__main__": 17 import sys 18 fib(int(5))
三、編譯模塊
python -O/-OO <文件>.py
a.模塊名區分大小寫,foo.py與FOO.py表明的是兩個模塊
b.你可使用-O或者-OO轉換python命令來減小編譯模塊的大小
-O轉換會幫你去掉assert語句
-OO轉換會幫你去掉assert語句和__doc__文檔字符串
因爲一些程序可能依賴於assert語句或文檔字符串,你應該在在確認須要的狀況下使用這些選項。
c.在速度上從.pyc文件中讀指令來執行不會比從.py文件中讀指令執行更快,只有在模塊被加載時,.pyc文件纔是更快的
d.只有使用import語句是纔將文件自動編譯爲.pyc文件,在命令行或標準輸入中指定運行腳本則不會生成這類文件,於是咱們可使用compieall模塊爲一個目錄中的全部模塊建立.pyc文件
模塊能夠做爲一個腳本(使用python -m compileall)編譯Python源
python -m compileall /module_directory 遞歸着編譯
若是使用python -O -m compileall /module_directory -l則只一層
命令行裏使用compile()函數時,自動使用python -O -m compileall
四、dir函數
內建函數dir是用來查找模塊中定義的名字,返回一個有序字符串列表
import spam
dir(spam)
若是沒有參數,dir()列舉出當前定義的名字。dir()不會列舉出內建函數或者變量的名字,它們都被定義到了標準模塊builtin中,能夠列舉出它們,
import builtins
dir(builtins)
Packages are a way of structuring Python’s module namespace by using 「dotted module names」
包是一種經過使用‘.模塊名’來組織python模塊名稱空間的方式。即所謂Package, 就是一堆module的集合,也就一堆.py文件。 你能夠用以下方式來建立一個package
a.不管是import形式仍是from...import形式,凡是在導入語句中(而不是在使用時)遇到帶點的,都要第一時間提升警覺:這是關於包纔有的導入語法
b.包是目錄級的(文件夾級),文件夾是用來組成py文件(包的本質就是一個包含__init__.py文件的目錄)
c.import導入文件時,產生名稱空間中的名字來源於文件,import 包,產生的名稱空間的名字一樣來源於文件,即包下的__init__.py,導入包本質就是在導入該文件
包A和包B下有同名模塊也不會衝突,如A.a與B.a來自倆個命名空間
ps.注意事項
a.關於包相關的導入語句也分爲import和from ... import ...兩種,可是不管哪一種,不管在什麼位置,在導入時都必須遵循一個原則:凡是在導入時帶點的,點的左邊都必須是一個包,不然非法。能夠帶有一連串的點,如item.subitem.subsubitem,但都必須遵循這個原則。
b.對於導入後,在使用時就沒有這種限制了,點的左邊能夠是包,模塊,函數,類(它們均可以用點的方式調用本身的屬性)。
c.對比import item 和from item import name的應用場景:若是咱們想直接使用name那必須使用後者。
測試文件路徑及文件內容
文件內容:
1 # #policy.py 2 # def get(): 3 # print('from policy.py') 4 # 5 # #versions.py 6 # def create_resource(conf): 7 # print('from version.py: ',conf) 8 # 9 # #manage.py 10 # def main(): 11 # print('from manage.py') 12 # 13 # #models.py 14 # def register_models(engine): 15 # print('from models.py: ',engine)
一、包的調用方式
1 # import glance.db.models 2 # glance.db.models.register_models('mysql') 3 ''' 4 結果: 5 from models.py: mysql 6 '''
1 ''' 2 from... import... 3 ''' 4 from glance.db import models 5 models.register_models('mysql') 6 7 from glance.db.models import register_models 8 register_models('mysql') 9 ''' 10 結果: 11 from models.py: mysql 12 from models.py: mysql 13 '''
在api目錄中的__init__中寫入:
1 #在__init__.py中定義 2 x=10 3 4 def func(): 5 print('from api.__init.py') 6 7 __all__=['x','func','policy']
在packer.py文件中寫入:
1 # from glance.api import * 2 # print(x) # 在__init__中寫了,可調用 3 # print(func) # 在__init__中寫了,可執行 4 # print(policy.get()) # __all__ 中寫了,因此ok 5 # print(versions.create_resource) # 找不到 6 ''' 7 10 8 <function func at 0x000000717E09C9D8> 9 from policy.py 10 None 11 Traceback (most recent call last): 12 File "D:/old_boy/old_boy_17_05/包/packer.py", line 86, in <module> 13 print(versions.create_resource) 14 NameError: name 'versions' is not defined 15 '''
ps.無論是哪一種方式,只要是第一次導入包或者是包的任何其餘部分,都會依次執行包下的__init__.py文件(咱們能夠在每一個包的文件內都打印一行內容來驗證一下),這個文件能夠爲空,可是也能夠存放一些初始化包的代碼。
二、絕對導入和相對導入
咱們的最頂級包glance是寫給別人用的,而後在glance包內部也會有彼此之間互相導入的需求,這時候就有絕對導入和相對導入兩種方式:
絕對導入:以glance做爲起始
相對導入:用.或者..的方式最爲起始(只能在一個包中使用,不能用於不一樣目錄內)
例如:咱們在glance/api/version.py中想要導入glance/cmd/manage.py
1 # 絕對導入 2 from glance.cmd import manage 3 manage.main() 4 5 #相對導入 6 from ..db import models 7 models.register_models('mysql')
1 from glance.api import versions 2 ''' 3 結果: 4 from manage.py 5 from models.py: mysql 6 '''
ps.測試結果:注意必定要在於glance同級的文件中測試。
特別須要注意的是:能夠用import導入內置或者第三方模塊(已經在sys.path中),可是要絕對避免使用import來導入自定義包的子模塊(沒有在sys.path中),應該使用from... import ...的絕對或者相對導入,且包的相對導入只能用from的形式。
正則就是用一些具備特殊含義的符號組合到一塊兒(稱爲正則表達式)來描述字符或者字符串的方法。或者說:正則就是用來描述一類事物的規則。(在Python中)它內嵌在Python中,並經過 re 模塊實現。正則表達式模式被編譯成一系列的字節碼,而後由用 C 編寫的匹配引擎執行。
一、經常使用匹配模式(元字符)
模式 | 描述 |
---|---|
^ | 匹配字符串的開頭 |
$ | 匹配字符串的末尾。 |
. | 匹配任意字符,除了換行符,當re.DOTALL標記被指定時,則能夠匹配包括換行符的任意字符。 |
[...] | 用來表示一組字符,單獨列出:[amk] 匹配 'a','m'或'k' |
[^...] | 不在[]中的字符:[^abc] 匹配除了a,b,c以外的字符。 |
re* | 匹配0個或多個的表達式。 |
re+ | 匹配1個或多個的表達式。 |
re? | 匹配0個或1個由前面的正則表達式定義的片斷,非貪婪方式 |
re{ n} | |
re{ n,} | 精確匹配n個前面表達式。 |
re{ n, m} | 匹配 n 到 m 次由前面的正則表達式定義的片斷,貪婪方式 |
a| b | 匹配a或b |
(re) | G匹配括號內的表達式,也表示一個組 |
(?imx) | 正則表達式包含三種可選標誌:i, m, 或 x 。隻影響括號中的區域。 |
(?-imx) | 正則表達式關閉 i, m, 或 x 可選標誌。隻影響括號中的區域。 |
(?: re) | 相似 (...), 可是不表示一個組 |
(?imx: re) | 在括號中使用i, m, 或 x 可選標誌 |
(?-imx: re) | 在括號中不使用i, m, 或 x 可選標誌 |
(?#...) | 註釋. |
(?= re) | 前向確定界定符。若是所含正則表達式,以 ... 表示,在當前位置成功匹配時成功,不然失敗。但一旦所含表達式已經嘗試,匹配引擎根本沒有提升;模式的剩餘部分還要嘗試界定符的右邊。 |
(?! re) | 前向否認界定符。與確定界定符相反;當所含表達式不能在字符串當前位置匹配時成功 |
(?> re) | 匹配的獨立模式,省去回溯。 |
\w | 匹配字母數字 |
\W | 匹配非字母數字 |
\s | 匹配任意空白字符,等價於 [\t\n\r\f]. |
\S | 匹配任意非空字符 |
\d | 匹配任意數字,等價於 [0-9]. |
\D | 匹配任意非數字 |
\A | 匹配字符串開始 |
\Z | 匹配字符串結束,若是是存在換行,只匹配到換行前的結束字符串。c |
\z | 匹配字符串結束 |
\G | 匹配最後匹配完成的位置。 |
\b | 匹配一個單詞邊界,也就是指單詞和空格間的位置。例如, 'er\b' 能夠匹配"never" 中的 'er',但不能匹配 "verb" 中的 'er'。 |
\B | 匹配非單詞邊界。'er\B' 能匹配 "verb" 中的 'er',但不能匹配 "never" 中的 'er'。 |
\n, \t, 等. | 匹配一個換行符。匹配一個製表符。等 |
\1...\9 | 匹配第n個分組的子表達式。 |
\10 | 匹配第n個分組的子表達式,若是它經匹配。不然指的是八進制字符碼的表達式。 |
1 # =================================匹配模式================================= 2 #一對一的匹配 3 # 'hello'.replace(old,new) 4 # 'hello'.find('pattern') 5 6 #正則匹配 7 import re 8 #\w與\W 9 print(re.findall('\w','hello egon 123')) #['h', 'e', 'l', 'l', 'o', 'e', 'g', 'o', 'n', '1', '2', '3'] 10 print(re.findall('\W','hello egon 123')) #[' ', ' '] 11 12 #\s與\S 13 print(re.findall('\s','hello egon 123')) #[' ', ' ', ' ', ' '] 14 print(re.findall('\S','hello egon 123')) #['h', 'e', 'l', 'l', 'o', 'e', 'g', 'o', 'n', '1', '2', '3'] 15 16 #\d與\D 17 print(re.findall('\d','hello egon 123')) #['1', '2', '3'] 18 print(re.findall('\D','hello egon 123')) #['h', 'e', 'l', 'l', 'o', ' ', 'e', 'g', 'o', 'n', ' '] 19 20 #\A與\D 21 print(re.findall('\Ahe','hello egon 123')) #['he'],\A==>^ 22 print(re.findall('123\Z','hello egon 123')) #['he'],\Z==>$ 23 24 #\n與\t 25 print(re.findall(r'\n','hello egon \n123')) #['\n'] 26 print(re.findall(r'\t','hello egon\t123')) #['\n'] 27 28 #^與$ 29 print(re.findall('^h','hello egon 123')) #['h'] 30 print(re.findall('3$','hello egon 123')) #['3'] 31 32 # 重複匹配:| . | * | ? | .* | .*? | + | {n,m} | 33 #. 34 print(re.findall('a.b','a1b')) #['a1b'] 35 print(re.findall('a.b','a\nb')) #[] 36 print(re.findall('a.b','a\nb',re.S)) #['a\nb'] 37 print(re.findall('a.b','a\nb',re.DOTALL)) #['a\nb']同上一條意思同樣 38 39 #* 40 print(re.findall('ab*','bbbbbbb')) #[] 41 print(re.findall('ab*','a')) #['a'] 42 print(re.findall('ab*','abbbb')) #['abbbb'] 43 44 #? 45 print(re.findall('ab?','a')) #['a'] 46 print(re.findall('ab?','abbb')) #['ab'] 47 #匹配全部包含小數在內的數字 48 print(re.findall('\d+\.?\d*',"asdfasdf123as1.13dfa12adsf1asdf3")) #['123', '1.13', '12', '1', '3'] 49 50 #.*默認爲貪婪匹配 51 print(re.findall('a.*b','a1b22222222b')) #['a1b22222222b'] 52 53 #.*?爲非貪婪匹配:推薦使用 54 print(re.findall('a.*?b','a1b22222222b')) #['a1b'] 55 56 #+ 57 print(re.findall('ab+','a')) #[] 58 print(re.findall('ab+','abbb')) #['abbb'] 59 60 #{n,m} 61 print(re.findall('ab{2}','abbb')) #['abb'] 62 print(re.findall('ab{2,4}','abbb')) #['abb'] 63 print(re.findall('ab{1,}','abbb')) #'ab{1,}' ===> 'ab+' 64 print(re.findall('ab{0,}','abbb')) #'ab{0,}' ===> 'ab*' 65 66 #[] 67 print(re.findall('a[1*-]b','a1b a*b a-b')) #[]內的都爲普通字符了,且若是-沒有被轉意的話,應該放到[]的開頭或結尾 68 print(re.findall('a[^1*-]b','a1b a*b a-b a=b')) #[]內的^表明的意思是取反,因此結果爲['a=b'] 69 print(re.findall('a[0-9]b','a1b a*b a-b a=b')) #[]內的^表明的意思是取反,因此結果爲['a=b'] 70 print(re.findall('a[a-z]b','a1b a*b a-b a=b aeb')) #[]內的^表明的意思是取反,因此結果爲['a=b'] 71 print(re.findall('a[a-zA-Z]b','a1b a*b a-b a=b aeb aEb')) #[]內的^表明的意思是取反,因此結果爲['a=b'] 72 73 #\# print(re.findall('a\\c','a\c')) #對於正則來講a\\c確實能夠匹配到a\c,可是在python解釋器讀取a\\c時,會發生轉義,而後交給re去執行,因此拋出異常 74 print(re.findall(r'a\\c','a\c')) #r表明告訴解釋器使用rawstring,即原生字符串,把咱們正則內的全部符號都當普通字符處理,不要轉義 75 print(re.findall('a\\\\c','a\c')) #同上面的意思同樣,和上面的結果同樣都是['a\\c'] 76 77 #():分組 78 print(re.findall('ab+','ababab123')) #['ab', 'ab', 'ab'] 79 print(re.findall('(ab)+123','ababab123')) #['ab'],匹配到末尾的ab123中的ab 80 print(re.findall('(?:ab)+123','ababab123')) #findall的結果不是匹配的所有內容,而是組內的內容,?:可讓結果爲匹配的所有內容 81 82 #| 83 print(re.findall('compan(?:y|ies)','Too many companies have gone bankrupt, and the next one is my company')) 84 #['companies', 'company']
二、re模塊提供的方法介紹
1 # ===========================re模塊提供的方法介紹=========================== 2 import re 3 #1 findall 4 print(re.findall('e','alex make love') ) #['e', 'e', 'e'],返回全部知足匹配條件的結果,放在列表裏 5 #2 search 6 print(re.search('e','alex make love').group()) #e,只到找到第一個匹配而後返回一個包含匹配信息的對象,該對象能夠經過調用group()方法獲得匹配的字符串,若是字符串沒有匹配,則返回None。 7 8 #3 match 9 print(re.match('e','alex make love')) #None,同search,不過在字符串開始處進行匹配,徹底能夠用search+^代替match 10 11 #4 split 12 print(re.split('[ab]','abcd')) #['', '', 'cd'],先按'a'分割獲得''和'bcd',再對''和'bcd'分別按'b'分割 13 14 #5 sub 15 print('===>',re.sub('a','A','alex make love')) #===> Alex mAke love,不指定n,默認替換全部 16 print('===>',re.sub('a','A','alex make love',1)) #===> Alex make love 17 print('===>',re.sub('a','A','alex make love',2)) #===> Alex mAke love 18 print('===>',re.sub('^(\w+)(.*?\s)(\w+)(.*?\s)(\w+)(.*?)$',r'\5\2\3\4\1','alex make love')) #===> love make alex 19 20 print('===>',re.subn('a','A','alex make love')) #===> ('Alex mAke love', 2),結果帶有總共替換的個數 21 22 23 #6 compile 24 obj=re.compile('\d{2}') 25 26 print(obj.search('abc123eeee').group()) #12 27 print(obj.findall('abc123eeee')) #['12'],重用了obj 28 29 # 7 應用 30 print(re.findall("<(?P<tag_name>\w+)>\w+</(?P=tag_name)>","<h1>hello</h1>")) #['h1'] 31 print(re.search("<(?P<tag_name>\w+)>\w+</(?P=tag_name)>","<h1>hello</h1>").group()) #<h1>hello</h1> 32 print(re.search("<(?P<tag_name>\w+)>\w+</(?P=tag_name)>","<h1>hello</h1>").groupdict()) #<h1>hello</h1> 33 34 print(re.search(r"<(\w+)>\w+</(\w+)>","<h1>hello</h1>").group()) 35 print(re.search(r"<(\w+)>\w+</\1>","<h1>hello</h1>").group()) 36 37 print(re.findall(r'-?\d+\.?\d*',"1-12*(60+(-40.35/5)-(-4*3))")) #找出全部數字['1', '-12', '60', '-40.35', '5', '-4', '3'] 38 39 #使用|,先匹配的先生效,|左邊是匹配小數,而findall最終結果是查看分組,全部即便匹配成功小數也不會存入結果 40 #而不是小數時,就去匹配(-?\d+),匹配到的天然就是,非小數的數,在此處即整數 41 print(re.findall(r"-?\d+\.\d*|(-?\d+)","1-2*(60+(-40.35/5)-(-4*3))")) #找出全部整數['1', '-2', '60', '', '5', '-4', '3']
三、應用練習
#########################應用練習############################################### #_*_coding:utf-8_*_ #在線調試工具:tool.oschina.net/regex/# import re s=''' http://www.baidu.com egon@oldboyedu.com 你好 010-3141 ''' #最常規匹配 # content='Hello 123 456 World_This is a Regex Demo' # res=re.match('Hello\s\d\d\d\s\d{3}\s\w{10}.*Demo',content) # print(res) # print(res.group()) # # 返回一個tuple表示(m.start(), m.end()) # print(res.span()) ''' 結果: <_sre.SRE_Match object; span=(0, 40), match='Hello 123 456 World_This is a Regex Demo'> Hello 123 456 World_This is a Regex Demo (0, 40) ''' #泛匹配 # content='Hello 123 456 World_This is a Regex Demo' # res=re.match('^Hello.*Demo',content) # print(res.group()) ''' 結果: Hello 123 456 World_This is a Regex Demo ''' #匹配目標,得到指定數據 # content='Hello 123 456 World_This is a Regex Demo' # res=re.match('^Hello\s(\d+)\s(\d+)\s.*Demo',content) # print(res.group()) #取全部匹配的內容 # print(res.group(1)) #取匹配的第一個括號內的內容 # print(res.group(2)) #去陪陪的第二個括號內的內容 ''' 結果: Hello 123 456 World_This is a Regex Demo 123 456 ''' #貪婪匹配:.*表明匹配儘量多的字符 # import re # content='Hello 123 456 World_This is a Regex Demo' # # res=re.match('^He.*(\d+).*Demo$',content) # print(res.group(1)) #只打印6,由於.*會盡量多的匹配,而後後面跟至少一個數字 ''' 結果: 6 ''' #非貪婪匹配:?匹配儘量少的字符 # import re # content='Hello 123 456 World_This is a Regex Demo' # # res=re.match('^He.*?(\d+).*Demo$',content) # print(res.group(1)) #只打印6,由於.*會盡量多的匹配,而後後面跟至少一個數字 ''' 結果: 123 ''' #匹配模式:.不能匹配換行符 content='''Hello 123456 World_This is a Regex Demo ''' # res=re.match('He.*?(\d+).*?Demo$',content) # print(res) #輸出None # # res=re.match('He.*?(\d+).*?Demo$',content,re.S) #re.S讓.能夠匹配換行符 # print(res) # print(res.group(1)) ''' 結果: None <_sre.SRE_Match object; span=(0, 39), match='Hello 123456 World_This\nis a Regex Demo'> 123456 ''' #轉義:\ # content='price is $5.00' # res=re.match('price is $5.00',content) # print(res) # # res=re.match('price is \$5\.00',content) # print(res) ''' 結果: None <_sre.SRE_Match object; span=(0, 14), match='price is $5.00'> ''' #總結:儘可能精簡,詳細的以下 # 儘可能使用泛匹配模式.* # 儘可能使用非貪婪模式:.*? # 使用括號獲得匹配目標:用group(n)去取得結果 # 有換行符就用re.S:修改模式 #re.search:會掃描整個字符串,不會從頭開始,找到第一個匹配的結果就會返回 # import re # content='Extra strings Hello 123 456 World_This is a Regex Demo Extra strings' # # res=re.match('Hello.*?(\d+).*?Demo',content) # print(res) #輸出結果爲None # # import re # content='Extra strings Hello 123 456 World_This is a Regex Demo Extra strings' # # res=re.search('Hello.*?(\d+).*?Demo',content) # # print(res.group(1)) #輸出結果爲123 #re.search:只要一個結果,匹配演練, # import re # content=''' # <tbody> # <tr id="4766303201494371851675" class="even "><td><div class="hd"><span class="num">1</span><div class="rk "><span class="u-icn u-icn-75"></span></div></div></td><td class="rank"><div class="f-cb"><div class="tt"><a href="/song?id=476630320"><img class="rpic" src="http://p1.music.126.net/Wl7T1LBRhZFg0O26nnR2iQ==/19217264230385030.jpg?param=50y50&quality=100"></a><span data-res-id="476630320" ''' # res=re.search('<a\shref=.*?<b\stitle="(.*?)".*?b>',content) # print(res.group(1)) ''' 結果: Traceback (most recent call last): File "D:/old_boy/old_boy_17_05/re_mod.py", line 281, in <module> print(res.group(1)) AttributeError: 'NoneType' object has no attribute 'group' ''' # re.findall:找到符合條件的全部結果 # res=re.findall('<a\shref=.*?<b\stitle="(.*?)".*?b>',content) # for i in res: # print(i) ''' 結果: 空 ''' #re.sub:字符串替換 # import re # content='Extra strings Hello 123 456 World_This is a Regex Demo Extra strings' # # content=re.sub('\d+','',content) # print(content) ''' 結果: Extra strings Hello World_This is a Regex Demo Extra strings ''' #用\1取得第一個括號的內容 #用法:將123與456換位置 # import re # content='Extra strings Hello 123 456 World_This is a Regex Demo Extra strings' # # # content=re.sub('(Extra.*?)(\d+)(\s)(\d+)(.*?strings)',r'\1\4\3\2\5',content) # content=re.sub('(\d+)(\s)(\d+)',r'\3\2\1',content) # print(content) ''' 結果: Extra strings Hello 456 123 World_This is a Regex Demo Extra strings ''' # import re # content='Extra strings Hello 123 456 World_This is a Regex Demo Extra strings' # # res=re.search('Extra.*?(\d+).*strings',content) # print(res.group(1)) ''' 結果: 123 ''' # import requests,re # respone=requests.get('https://book.douban.com/').text # # print(respone) # print('======'*1000) # print('======'*1000) # print('======'*1000) # print('======'*1000) # res=re.findall('<li.*?cover.*?href="(.*?)".*?title="(.*?)">.*?more-meta.*?author">(.*?)</span.*?year">(.*?)</span.*?publisher">(.*?)</span.*?</li>',respone,re.S) # # res=re.findall('<li.*?cover.*?href="(.*?)".*?more-meta.*?author">(.*?)</span.*?year">(.*?)</span.*?publisher">(.*?)</span>.*?</li>',respone,re.S) # # # for i in res: # print('%s %s %s %s' %(i[0].strip(),i[1].strip(),i[2].strip(),i[3].strip()))