導語:本文章記錄了本人在學習Python基礎之函數篇的重點知識及我的心得,打算入門Python的朋友們能夠來一塊兒學習並交流。
本文重點:python
一、掌握裝飾器的本質、功能和特色;
二、瞭解閉包的概念以及Python變量調用規則;
三、瞭解並學會使用標準庫中重要的裝飾器;
四、掌握參數化裝飾器的意義和代碼實現方式。
裝飾器功能(decorator):將被裝飾的函數看成參數傳遞給與裝飾器對應的函數(名稱相同的函數),並返回包裝後的被裝飾的函數。
裝飾器本質:是一個返回函數的高階函數。
裝飾器特色:緩存
一、多數裝飾器會把被裝飾的函數替換成其餘函數
二、函數裝飾器在導入模塊時當即執行,而被裝飾的函數只在明確調用時執行。
裝飾器有時採用嵌套函數表示的緣由(我的理解):
一些裝飾器的裝飾功能只有在被裝飾函數被調用時方可觸發,所以須要用嵌套函數的形式來編寫。閉包
自由變量(free variable):指未在本地做用域綁定的變量,介於局部變量和全局變量之間。
變量查找規則:在python中, 一個變量的查找順序是 LEGB (L:Local 局部環境,E:Enclosing 閉包,G:Global 全局,B:Built-in 內建).函數
閉包:引用了自由變量的函數。學習
閉包的做用:ui
不一樣的是父函數只在調用時執行,執行完畢後其環境就會釋放,而類則在文件執行時建立,通常程序執行完畢後做用域才釋放。
nonlocal聲明:能夠將局部變量聲明爲自由變量。spa
eg:計算移動平均值的高階函數:code
def averager(): sum=0 n=0 def avg(i): nonlocal sum,n sum+=i n+=1 return print(sum/n) return avg a=averager() a(3) a(5) a(7)
輸出分別是3,4,5orm
Python內置了三個用於裝飾方法的函數:property,classmethod和staticmethod
三個重要的內置裝飾器:對象
能夠把被裝飾對象的相關屬性複製到裝飾器中
,默認有 __module__、__name__、__doc__。實現備忘功能,即緩存,避免發生重複調用來提升效率。
注意調用時必須帶括號
,由於此裝飾器包含maxsize和typed兩個參數,帶括號表示使用默認參數。不然 functools.lru_cache不清楚該如何執行。以functools.lru_cache爲例實現斐波那契函數的計時裝飾器:.
import time import functools def clock(func): @functools.lru_cache()#減小重複自引用,避免重複計算 def clocked(arg): t0=time.perf_counter() func(arg) result=func(arg) t1=time.perf_counter() processtime=t1-t0 name=func.__name__ print("[{0:.8f}] {1}({2})={3}".format(processtime,name,arg,result)) return result#很是重要,不然破壞原fibs函數致使沒法遞歸調用。 return clocked @clock def fibs(n): if n<2: return 1 else: return fibs(n-1)+fibs(n-2) fibs(6)#輸出8
如同函數能夠嵌套使用,裝飾器亦能夠疊放起來裝飾同一對象。語法以下:
@d1
@d2
def f1():
pass
上述裝飾操做等價於d1(d2(f)),故易知疊放在上端的裝飾器靠後執行。
普通裝飾器的進階版,經過參數接口能夠更方便的定製咱們須要的裝飾器,適應需求變化。代碼實現較普通裝飾器多嵌套一層函數,用來傳遞用戶輸入的參數。
以計時器舉例形式以下:
import time DEFAULT_FMT = '[{elapsed:0.8f}s] {name}({args}) -> {result}' def clock(fmt=DEFAULT_FMT): #三層函數來實現 def decorate(func): def clocked(*_args): t0 = time.time() _result = func(*_args) elapsed = time.time() - t0 name = func.__name__ args = ', '.join(repr(arg) for arg in _args) result = repr(_result) print(fmt.format(**locals())) return _result return clocked return decorate if __name__ == '__main__': @clock() def snooze(seconds): time.sleep(seconds) for i in range(3): snooze(.123)
輸出:
[0.12480044s] snooze(0.123) -> None [0.13660240s] snooze(0.123) -> None [0.12480044s] snooze(0.123) -> None
上邊實現參數化裝飾器的代碼因爲包含三重嵌套略顯複雜, 事實上覆雜的裝飾器用 class 實現更方便。經過 __call__ 方法便可改寫參數化裝飾器。具體實現留做勤勞的你去課後思考,感興趣的能夠與我私信交流。