Python學習之進階函數詳解

來源:互聯網
上載者:User

標籤:

本文和大家分享的主要是python自動化營運中進階函數相關內容,一起來看看吧,希望對大家學習python有所協助。 一、協程 1.1協程的概念 協程,又稱微線程,纖程。英文名Coroutine。一句話說明什麼是線程:協程是一種使用者態的輕量級線程。(其實並沒有說明白~) 那麼這麼來理解協程比較容易: 線程是系統層級的,它們是由作業系統調度;協程是程式層級的,由程式員根據需要自己調度。我們把一個線程中的一個個函數叫做子程式,那麼子程式在執行過程中可以中斷去執行別的子程式;別的子程式也可以中斷回來繼續執行之前的子程式,這就是協程。也就是說同一線程下的一段代碼執行著執行著就可以中斷,然後跳去執行另一段代碼,當再次回來執行代碼塊的時候,接著從之前中斷的地方開始執行。 比較專業的理解是: 協程擁有自己的寄存器上下文和棧。協程調度切換時,將寄存器上下文和棧儲存到其他地方,在切回來的時候,恢複先前儲存的寄存器上下文和棧。因此:協程能保留上一次調用時的狀態(即所有局部狀態的一個特定組合),每次過程重入時,就相當於進入上一次調用的狀態,換種說法:進入上一次離開時所處邏輯流的位置。 1.2 協程的優缺點 協程的優點: (1)無需線程環境切換的開銷,協程避免了無意義的調度,由此可以提高效能(但也因此,程式員必須自己承擔調度的責任,同時,協程也失去了標準線程使用多CPU的能力) (2)無需原子伺服器用戶端檔案鎖及同步的開銷 (3)方便切換控制流程,簡化編程模型 (4)高並發+高擴充性+低成本:一個CPU支援上萬的協程都不是問題。所以很適合用於高並發處理。 協程的缺點: (1)無法利用多核資源:協程的本質是個單線程,它不能同時將 單個CPU 的多個核用上,協程需要和進程配合才能運行在多CPU上.當然我們日常所編寫的絕大部分應用都沒有這個必要,除非是cpu密集型應用。 (2)進行阻塞(Blocking)操作(如IO時)會阻塞掉整個程式 2、Python中如何?協程 2.1 yield實現協程 前文所述“子程式(函數)在執行過程中可以中斷去執行別的子程式;別的子程式也可以中斷回來繼續執行之前的子程式”,那麼很容易想到Python的yield,顯然yield是可以實現這種切換的。 def eater(name): print("%s eat food" %name) while True: food = yield print("done") g = eater("gangdan") print(g) 執行結果: <generator object eater at 0x0000000002140FC0> 由執行結果可以證明g現在就是產生器函數 2.2 協程函數賦值過程 用的是yield的運算式形式,要先運行next(),讓函數初始化並停在yield,然後再send() ,send會在觸發下一次代碼的執行時,給yield賦值 next()和send() 都是讓函數在上次暫停位置繼續運行, def creater(name): print(’%s start to eat food’ %name) food_list = [] while True: food = yield food_list print(’%s get %s ,to start eat’ %(name,food)) food_list.append(food)# 擷取產生器 builder = creater(’tom’)# 現在是運行函數,讓函數初始化 next(builder) print(builder.send(’包子’)) print(builder.send(’骨頭’)) print(builder.send(’菜湯’)) 執行結果: tom start to eat food tom get 包子 ,to start eat [’包子 tom get 骨頭 ,to start eat [’包子’, ’骨頭 tom get 菜湯 ,to start eat [’包子’, ’骨頭’, ’菜湯 需要注意的是每次都需要先運行next()函數,讓程式停留在yield位置。 如果有多個這樣的函數都需要執行next()函數,讓程式停留在yield位置。為了防止忘記初始化next操作,需要用到裝飾器來解決此問題 def init(func): def wrapper(*args,**kwargs): builder = func(*args,**kwargs) next(builder)    # 這個地方是關鍵可以使用builder.send("None"),第一次必須傳入None。 return builder return [email protected] creater(name): print(’%s start to eat food’ %name) food_list = [] while True: food = yield food_list print(’%s get %s ,to start eat’ %(name,food)) food_list.append(food)# 擷取產生器 builder = creater("tom")# 現在是直接運行函數,無須再函數初始化 print(builder.send(’包子’)) print(builder.send(’骨頭’)) print(builder.send(’菜湯’)) 執行結果: tom start to eat food tom get 包子 ,to start eat [’包子 tom get 骨頭 ,to start eat [’包子’, ’骨頭 tom get 菜湯 ,to start eat [’包子’, ’骨頭’, ’菜湯 2.3 協程函數簡單應用 請給Tom投餵食物 def init(func): def wrapper(*args,**kwargs): builder = func(*args,**kwargs) next(builder) return builder return [email protected] creater(name): print(’%s start to eat food’ %name) food_list = [] while True: food = yield food_list print(’%s get %s ,to start eat’ %(name,food)) food_list.append(food)def food(): builder = creater("Tom") while True: food = input("請給Tom投餵食物:").strip() if food == "q": print("投喂結束") return 0 else: builder.send(food)if __name__ == ’__main__’: food() 執行結果: Tom start to eat food 請給Tom投餵食物:骨頭 Tom get 骨頭 ,to start eat 請給Tom投餵食物:菜湯 Tom get 菜湯 ,to start eat 請給Tom投餵食物:q 投喂結束 2.4 協程函數的應用 實現linux中"grep -rl error <目錄>"命令,過濾一個檔案下的子檔案、字檔案夾的內容中的相應的內容的功能程式 首先瞭解一個OS模組中的walk方法,能夠把參數中的路徑下的檔案夾開啟並返回一個元組 >>> import os # 匯入模組>>> os.walk(r"E:\Python\script") #使用r 是讓字串中的符號沒有特殊意義,針對的是轉義 >>> g = os.walk(r"E:\Python\script")>>> next(g) (’E:\\Python\\script’, [’.idea’, ’函數’], []) 返回的是一個元組,第一個元素是檔案的路徑,第二個是檔案夾,第三個是該路徑下的檔案 這裡需要用到一個寫程式的思想:面向過程編程 二、面向過程編程 面向過程:核心是過程二字,過程及即解決問題的步驟,基於面向過程設計程式就是一條工業流水線,是一種機械式的思維方式。流水線式的編程思想,在設計程式時,需要把整個流程設計出來 優點: 1:體繫結構更加清晰 2:簡化程式的複雜度 缺點: 可擴充性極其的差,所以說面向過程的應用情境是:不需要經常變化的軟體,如:linux核心,httpd,git等軟體 下面就根據面向過程的思想完成協程函數應用中的功能 目錄結構: test ├── aa │   ├── bb1 │    │    └── file2.txt │   └── bb2 │       └── file3.txt └─ file1.txt 檔案內容:file1.txt:error123file2.txt:123file3.txt:123error 程式流程 第一階段:找到所有檔案的絕對路徑 第二階段:開啟檔案 第三階段:迴圈讀取每一行 第四階段:過濾“error” 第五階段:列印該行屬於的檔案名稱 第一階段:找到所有檔案的絕對路徑 g是一個產生器,就能夠用next()執行,每次next就是運行一次,這裡的運行結果是依次開啟檔案的路徑 >>> import os>>> g = os.walk(r"E:\Python\script\函數\test")>>> next(g) (’E:\\Python\\script\\函數\\test’, [’aa’], [])>>> next(g) (’E:\\Python\\script\\函數\\test\\aa’, [’bb1’, ’bb2’], [’file1.txt’])>>> next(g) (’E:\\Python\\script\\函數\\test\\aa\\bb1’, [], [’file2.txt’])>>> next(g) (’E:\\Python\\script\\函數\\test\\aa\\bb2’, [], [’file3.txt’])>>> next(g) Traceback (most recent call last): File "file:///C:\Users\wlc\AppData\Local\Temp\ksohtml\wps86F5.tmp.wmf", line 1, in StopIteration 我們在開啟檔案的時候需要找到檔案的絕對路徑,現在可以通過字串拼接的方法把第一部分和第三部分進行拼接 用迴圈開啟: import os dir_g = os.walk(r"E:\Python\script\函數\test")for dir_path in dir_g: print(dir_path) 結果: (’E:\\Python\\script\\函數\\test’, [’aa’], []) (’E:\\Python\\script\\函數\\test\\aa’, [’bb1’, ’bb2’], [’file1.txt’]) (’E:\\Python\\script\\函數\\test\\aa\\bb1’, [], [’file2.txt’]) (’E:\\Python\\script\\函數\\test\\aa\\bb2’, [], [’file3.txt’]) 將查詢出來的檔案和路徑進行拼接,拼接成絕對路徑 import os dir_g = os.walk(r"E:\Python\script\函數\test")for dir_path in dir_g: for file in dir_path[2]: file = "%s\\%s" %(dir_path[0],file) print(file) 執行結果: E:\Python\script\函數\test\aa\file1.txtE:\Python\script\函數\test\aa\bb1\file2.txtE:\Python\script\函數\test\aa\bb2\file3.txt 用函數實現: import osdef search(): while True: dir_name = yield dir_g = os.walk(dir_name) for dir_path in dir_g: for file in dir_path[2]: file = "%s\\%s" %(dir_path[0],file) print(file) g = search() next(g) g.send(r"E:\Python\script\函數\test") 為了把結果返回給下一流程 @init   # 初始化產生器def search(target): while True: dir_name = yield dir_g = os.walk(dir_name) for pardir,_,files in dir_g: for file in files: abspath = r"%s\%s" %(pardir,file) target.send(abspath) 第二階段:開啟檔案 @initdef opener(target): while True: abspath=yield with open(abspath,’rb’) as f: target.send((abspath,f)) 第三階段:迴圈讀出每一行內容 @initdef cat(target): while True: abspath,f=yield #(abspath,f) for line in f: res=target.send((abspath,line)) if res:break 第四階段:過濾 @initdef grep(pattern,target): tag=False while True: abspath,line=yield tag tag=False if pattern in line: target.send(abspath) tag=True 第五階段:列印該行屬於的檔案名稱 @initdef printer(): while True: abspath=yield print(abspath) g = search(opener(cat(grep(’error’.encode(’utf-8’), printer())))) g.send(r’E:\Python\script\函數\test’) 執行結果:E:\Python\script\函數\test\aa\file1.txtE:\Python\script\函數\test\aa\bb2\file3.txt
來源:51CTO

Python學習之進階函數詳解

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

Tags Index: