摘要:變量查找規則在中一個變量的查找順序是局部環境,閉包,全局,內建閉包引用了自由變量的函數。閉包的作用閉包的最大特點是可以將父函數的變量與內部函數綁定,并返回綁定變量后的函數,此時即便生成閉包的環境父函數已經釋放,閉包仍然存在。
導語:本文章記錄了本人在學習Python基礎之函數篇的重點知識及個人心得,打算入門Python的朋友們可以來一起學習并交流。
本文重點:
1、掌握裝飾器的本質、功能和特點;一、裝飾器基礎知識
2、了解閉包的概念以及Python變量調用規則;
3、了解并學會使用標準庫中重要的裝飾器;
4、掌握參數化裝飾器的意義和代碼實現方式。
裝飾器功能(decorator):將被裝飾的函數當作參數傳遞給與裝飾器對應的函數(名稱相同的函數),并返回包裝后的被裝飾的函數。
裝飾器本質:是一個返回函數的高階函數。
裝飾器特點:
1、多數裝飾器會把被裝飾的函數替換成其他函數
2、函數裝飾器在導入模塊時立即執行,而被裝飾的函數只在明確調用時執行。
裝飾器有時采用嵌套函數表示的原因(個人理解):
一些裝飾器的裝飾功能只有在被裝飾函數被調用時方可觸發,因此需要用嵌套函數的形式來編寫。
自由變量(free variable):指未在本地作用域綁定的變量,介于局部變量和全局變量之間。
變量查找規則:在python中, 一個變量的查找順序是 LEGB (L:Local 局部環境,E:Enclosing 閉包,G:Global 全局,B:Built-in 內建).
閉包:引用了自由變量的函數。
閉包的作用:
閉包的最大特點是可以將父函數的變量與內部函數綁定,并返回綁定變量后的函數,此時即便生成閉包的環境(父函數)已經釋放,閉包仍然存在。
這個過程很像類(父函數)生成實例(閉包),不同的是父函數只在調用時執行,執行完畢后其環境就會釋放,而類則在文件執行時創建,一般程序執行完畢后作用域才釋放。
因此對一些需要重用的功能且不足以定義為類的行為,使用閉包會比使用類占用更少的資源,且更輕巧靈活。
nonlocal聲明:可以將局部變量聲明為自由變量。
eg:計算移動平均值的高階函數:
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,5
三、裝飾器進階使用 1.標準庫中的裝飾器Python內置了三個用于裝飾方法的函數:property,classmethod和staticmethod
三個重要的內置裝飾器:
functools.wraps:
(1)協助構建行為良好的裝飾器。
(2)可以把被裝飾對象的相關屬性復制到裝飾器中,默認有 __module__、__name__、__doc__。
(3)個人理解,裝飾器在實現裝飾的過程中意見把被裝飾函數替換了。此時你想調用被裝飾函數的__doc__和__name__會發現是none,此時通過functools.wraps就可以在裝飾時把相關屬性復制過來使用,避免這個問題發生。
functools.lru_cache
(1)實現備忘功能,即緩存,避免發生重復調用來提高效率。
(2)注意調用時必須帶括號,因為此裝飾器包含maxsize和typed兩個參數,帶括號表示使用默認參數。否則 functools.lru_cache不清楚該如何執行。
functools.singledispatch
為函數提供重載功能。被其裝飾的函數會成為泛函數(generic function):根據第一個參數的類型,用不同的方式執行相同操作的一組函數。
以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)#輸出82.疊放裝飾器
如同函數可以嵌套使用,裝飾器亦可以疊放起來裝飾同一對象。語法如下:
@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) -> None4.類裝飾器
上邊實現參數化裝飾器的代碼由于包含三重嵌套略顯復雜, 事實上復雜的裝飾器用 class 實現更方便。通過 __call__ 方法即可改寫參數化裝飾器。具體實現留作勤勞的你去課后思考,感興趣的可以與我私信交流。
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://m.specialneedsforspecialkids.com/yun/41475.html
摘要:初步認識裝飾器函數裝飾器用于在源代碼中標記函數,以某種方式增強函數的行為。函數裝飾器在導入模塊時立即執行,而被裝飾的函數只在明確調用時運行。只有涉及嵌套函數時才有閉包問題。如果想保留函數原本的屬性,可以使用標準庫中的裝飾器。 《流暢的Python》筆記本篇將從最簡單的裝飾器開始,逐漸深入到閉包的概念,然后實現參數化裝飾器,最后介紹標準庫中常用的裝飾器。 1. 初步認識裝飾器 函數裝飾...
摘要:函數裝飾器和閉包嚴格來說,裝飾器只是語法糖。何時執行裝飾器它們在被裝飾的函數定義之后立即運行。裝飾器突出了被裝飾的函數的作用,還便于臨時禁用某個促銷策略只需把裝飾器注釋掉。 函數裝飾器和閉包 嚴格來說,裝飾器只是語法糖。如前所示,裝飾器可以像常規的可調用對象那樣調用,其參數是另一個函數。有時,這樣做更方便,尤其是做元編程(在運行時改變程序的行為)時。 Python何時執行裝飾器 它們在...
摘要:迭代器迭代是訪問集合元素的一種方式。迭代器是一個可以記住遍歷的位置的對象,迭代器對象從集合的第一個元素開始訪問,直到所有的元素被訪問完結束,迭代器只往前不會往后退。生成器特點保存了一套生成數值的算法。 迭代器 迭代是訪問集合元素的一種方式。迭代器是一個可以記住遍歷的位置的對象,迭代器對象從集合的第一個元素開始訪問,直到所有的元素被訪問完結束,迭代器只往前不會往后退。 可迭代對象 以直接...
摘要:重寫內建名字空間中的函數閉包閉包是詞法閉包的簡稱。另一種說法認為閉包是由函數和與其相關的引用環境組合而成的實體。 Python 中的 Decorator(裝飾器) 是對一個函數或者方法的封裝,從而使其可以完成一些與自身功能無關的工作。 預備知識 一切皆對象 在 Python 中,所有的一切都被視為對象,任何的變量、函數、類等都是 object 的子類。因此除了變量之外,函數和類等也可以...
閱讀 3001·2021-10-13 09:39
閱讀 2698·2021-09-27 13:34
閱讀 2037·2019-08-30 15:55
閱讀 3266·2019-08-30 15:43
閱讀 3641·2019-08-30 11:16
閱讀 1757·2019-08-26 18:28
閱讀 1293·2019-08-26 13:56
閱讀 918·2019-08-26 13:35