標籤:python 函數 裝飾器 產生器 迭代器 可迭代對象 協程
Python學習之三大名器-裝飾器、迭代器、產生器
一、裝飾器
裝飾,顧名思義就是在原來的基礎上進行美化及完善,器這裡指函數,所以說裝飾器就是裝飾函數,也就是在不改變原來函數的代碼及調用方式的前提下對原函數進行功能上的完善。其核心原理其實是利用閉包。
格式 @關鍵字+裝飾函數
被裝飾函數()
注意:@行必須頂頭寫而且是在被裝飾函數的正上方
按照形式可以分為:無參裝飾器和有參裝飾器,有參裝飾器即給裝飾器加上參數
以下樣本是一個無參裝飾器,為原函數添加了統計已耗用時間的功能
import time#定義裝飾器 def timer(func): def wrapper(*args,**kwargs): start_time = time.time() res = func(*args,**kwargs) stop_time = time.time() print("run time is %s" %(stop_time-start_time)) return res return wrapper #調用裝飾器@timerdef index(): l = [] for i in range(10000000): l.append(i)#調用階段 index()
以下是一個有參裝飾器,實現簡單的認證功能,#數字表示程式依次執行順序
def auth2(auth_type): #1 #3 def auth(func): #4 #6 def wrapper(*args,**kwargs): #7 #10 if auth_type == ‘file‘: #11 name=input(‘username: ‘) password=input(‘password: ‘) if name == ‘zhejiangF4‘ and password == ‘666‘: print(‘auth successfull‘) res=func(*args,**kwargs) return res else: print(‘auth error‘) elif auth_type == ‘sql‘: #12 print(‘nothing!‘) #13 return wrapper #8 return auth #5 @auth2(auth_type=‘sql‘) #2def index(): print(‘welcome to inex page‘) index() #9
二、迭代器
迭代器(iterator)是一種對象,它能夠用來遍曆標準模板庫容器中的部分或全部元素,每個迭代器對象代表容器中的確定的地址。------百度百科
可迭代的:只要對象本身有__iter__方法,那它就是可迭代的
執行對象下的__iter__方法,得到的結果就是迭代器
為什麼要用迭代器:
優點
1:迭代器提供了一種不依賴於索引的取值方式,這樣就可以遍曆那些沒有索 引的可迭代對象了(字典,集合,檔案)
2:迭代器與列表比較,迭代器是惰性計算的,更節省記憶體
缺點:
1:無法擷取迭代器的長度,使用不如清單索引取值靈活
2:一次性的,只能往後取值,不能倒著取值
查看s對象是否是迭代器:print(isinstance(s,Iterator)) 返回True就是迭代器
from collections import Iterable,Iterators=‘hello‘l=[1,2,3]t=(1,2,3)d={‘a‘:1}set1={1,2,3,4}f=open(‘a.txt‘)
s.__iter__()l.__iter__() t.__iter__()d.__iter__()set1.__iter__()f.__iter__()print(isinstance(s,Iterable))print(isinstance(l,Iterable))print(isinstance(t,Iterable))print(isinstance(d,Iterable))print(isinstance(set1,Iterable))print(isinstance(f,Iterable))print(isinstance(s,Iterator))print(isinstance(l,Iterator))print(isinstance(t,Iterator))print(isinstance(d,Iterator))print(isinstance(set1,Iterator))print(isinstance(f,Iterator))
運行結果如下:
650) this.width=650;" title="QQ20170412194147.png" src="https://s2.51cto.com/wyfs02/M01/8F/F7/wKiom1juEpmyloHFAAAfNIJNLNA267.png" alt="wKiom1juEpmyloHFAAAfNIJNLNA267.png" />
可以看出,字串、列表、字典、集合、元組、檔案都是可迭代的,但是只有檔案是迭代器
三、產生器
通過列表產生式,我們可以直接建立一個列表。但是,受到記憶體限制,列表容量肯定是有限的。而且,建立一個包含100萬個元素的列表,不僅佔用很大的儲存空間,如果我們僅僅需要訪問前面幾個元素,那後面絕大多數元素佔用的空間都白白浪費了。
所以,如果列表元素可以按照某種演算法推算出來,那我們是否可以在迴圈的過程中不斷推算出後續的元素呢?這樣就不必建立完整的list,從而節省大量的空間。在Python中,這種一邊迴圈一邊計算的機制,稱為產生器:generator。
函數中包含yield語句的我們稱其為產生器函數
yield與return有何區別?
return只能返回一次函數就徹底結束了,而yield能返回多次值
yield到底幹了什麼事情:
yield把函數變成產生器(產生器就是迭代器)
函數在暫停以及繼續下一次運行時的狀態是由yield儲存
下例是兩個產生器的應用,一個用來不斷的輸入url,不斷的解析,另外一個則模仿Linux中的管道命令(實質是將一個函數的運行結果傳給下一個函數做處理,實現的比較簡單粗暴,多包涵,哈哈)
例1:
from urllib.request import urlopendef get(url): while True: def index(): return urlopen(url).read() url = yield index()g = get(‘http://www.baidu.com‘)next(g)def run(): while True: url = input("請輸入URL:") if ‘http://‘ not in url: print(g.send(‘http://‘+url)) else: print(g.send(url))run()
例2:
def cat(filename): with open(filename,‘r‘) as f: while True: line = f.readline() if not line: break else: yield linedef grep(string,lines): for line in lines: if string in line: yield lineg1 = cat(‘a.txt‘)g2 = grep(‘mac‘,g1)if __name__ == ‘__main__‘: m = input("請輸入命令:").strip() if m == "cat a.txt |grep mac": for i in g2: print(i)
補充:協程
如果在一個函數內部yield的使用方式是運算式形式的話,如x=yield,那麼該函數成為協程函數
直接看例子吧
def hello(func): def wrapper(*args,**kwargs): res = func(*args,**kwargs) next(res) return res return wrapper@hellodef eater(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) print(‘done‘)e=eater("somebody")print(e.send(‘巧克力‘))print(e.send("香蕉"))
Python學習之三大名器-裝飾器、迭代器、產生器