迭代器、生成器、裝飾器python
1、裝飾器算法
1、函數對象:能夠把函數名(不帶括號)當成變量去用,關聯的值是該函數的內存地址閉包
2、閉包函數=做用域+函數嵌套+函數對象app
核心點:內部函數傳參的關係查找是以定義階段爲準函數
3、什麼是閉包函數?工具
閉包是一個嵌套函數,內層函數調用了外層函數做用域的變量,外層函數返回值爲內層函數名。spa
實質:爲函數wrapper傳參的一種方式翻譯
「閉」函數指的是該函數是內嵌函數code
「包」函數指的是該函數包含對其外層函數做用域名字的引用orm
def outer(): x=1 def wrapper(): print(x) return wrapper f=outer() #爲何要返回函數名wrapper:打破內嵌函數wapper只能在outer函數內部調用的規則,使得重回全局調用 f()
4、閉包函數解決的痛點:當wrapper函數體須要傳參,又不能直接經過形參傳入時,閉包就能夠解決此問題
5、什麼是裝飾器?
定義一個函數(類),在不改變被裝飾函數源代碼及調用方式的狀況下爲其增長功能。
import time
def target(x,y): time.sleep(3) print("my name is {} ,age is {}".format(x,y)) return "ok"
#需求:不改變target函數源代碼和調用方式的狀況下統計target函數的運行時間 import time
def outer(func): #func體現閉包的功能,給wrapper函數體傳入須要的參數func,爲了避免改變target源碼 def wrapper(*args,**kwargs): #*args,**kwargs被裝飾函數須要的參數 start=time.time() res=func(*args,**kwargs) end=time.time() print(end-start) return res return wrapper #target=outer(target) #爲了避免改變target調用方式 #偷樑換柱:將target函數名指向的內存地址換成了wrapper @outer def target(x,y): time.sleep(3) print("my name is {} ,age is {}".format(x,y)) return "ok" target("lennie",28)#沒動源碼,也沒改變調用方式
6、無參裝飾器模板
def outer(func): def wrapper(*args,**kwargs): res=func(*args,**kwargs) return res return wrapper
7、有參裝飾器
在outer函數外再套一層函數outer2,將outer函數體須要的參數,經過outer2形參傳入,即成了有參裝飾器。
2、迭代器
1、迭代:每一次對過程的重複稱爲一次「迭代」,而與單純的重複不一樣,每一次迭代獲得的結果會做爲下一次迭代的初始值。
#重複 while True: msg = input('>>: ').strip() print(msg) #迭代 goods=['mac','lenovo','acer','dell','sony'] index=0 while index < len(goods): print(goods[index]) index+=1
2、可迭代對象:內置有__iter__()方法的對象都是可迭代對象,字符串、列表、元組、字典、集合、打開的文件都是可迭代對象,能夠直接被for循環遍歷。經過obj.__iter__()或者iter(obj)能夠返回一個迭代器對象iterator。
3、迭代器:迭代器即用來迭代取值的工具。是Python提供的一種統一的、不依賴於索引的迭代取值方式,只要存在多個「值」,不管序列類型仍是非序列類型均可以按照迭代器的方式取值。
四、迭代器對象:內置有__next__()方法的對象,能夠經過iterator.__next__()或者next(iterator)取出出迭代器中的下一個值,能夠直接被for循環遍歷。
>>> s={1,2,3} # 可迭代對象s >>> i=iter(s) # 本質就是在調用s.__iter__(),返回s的迭代器對象i, >>> next(i) # 本質就是在調用i.__next__() 1 >>> next(i) 2 >>> next(i) 3 >>> next(i) #拋出StopIteration的異常,表明無值可取,迭代結束
2、生成器
一、什麼是生成器/生成器對象?
生成器函數(含yield關鍵字)的返回值爲生成器對象,內置有__iter__()和__next__()方法,因此生成器自己就是一個迭代器,能夠直接被for循環遍歷。
>>> def my_range(start,stop,step=1): ... print('start...') ... while start < stop: ... yield start ... start+=step ... print('end...') ... >>> g=my_range(0,3) >>> g <generator object my_range at 0x104105678> #直接調用不執行函數體 >>> g.__iter__ <method-wrapper '__iter__' of generator object at 0x1037d2af0> >>> g.__next__ <method-wrapper '__next__' of generator object at 0x1037d2af0> >>> next(g) # 觸發函數執行直到遇到yield則中止,將yield後的值返回,並在當前位置掛起函數 start... 0 >>> next(g) # 再次調用next(g),函數從上次暫停的位置繼續執行,直到從新遇到yield... 1 >>> next(g) # 周而復始... 2 >>> next(g) # 觸發函數執行沒有遇到yield則無值返回,即取值完畢拋出異常結束迭代 end... Traceback (most recent call last): File "<stdin>", line 1, in <module> StopIteration
二、什麼是生成器函數:
(1) 調用生成器函數會自動建立迭代器對象。
(2) 調用迭代器對象的__next__()方法時才執行生成器函數。
(3) 每次執行到yield語句時返回數據,暫時離開。
(4) 待下次調用__next__()方法時繼續從離開處繼續執行。
三、做用:在循環過程當中,按照某種算法推算數據,沒必要建立容器存儲完整的結果,從而節省內存空間。數據量越大,優點越明顯。
四、生成器表達式
建立一個生成器對象有兩種方式,一種是調用帶yield關鍵字的函數,另外一種就是生成器表達式,與列表生成式的語法格式相同,只須要將[]換成(),即:
>>> [x*x for x in range(3)] [0, 1, 4] >>> g=(x*x for x in range(3)) >>> g <generator object <genexpr> at 0x101be0ba0> >>> next(g) #對比列表生成式,生成器表達式的優勢天然是節省內存(一次只產生一個值在內存中) 0 >>> next(g) 1 >>> next(g) 4 >>> next(g) #拋出異常StopIteration