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