国产成人精品久久免费动漫-国产成人精品天堂-国产成人精品区在线观看-国产成人精品日本-a级毛片无码免费真人-a级毛片毛片免费观看久潮喷

您的位置:首頁技術(shù)文章
文章詳情頁

Python學(xué)習(xí)筆記之裝飾器

瀏覽:71日期:2022-07-14 18:10:15

一. 什么是裝飾器

知乎某大佬如是說:內(nèi)褲可以用來遮羞,但是到了冬天它沒法為我們防風(fēng)御寒,聰明的人們發(fā)明了長褲,有了長褲后寶寶再也不冷了,裝飾器就像我們這里說的長褲,在不影響內(nèi)褲作用的前提下,給我們的身子提供了保暖的功效。裝飾器本質(zhì)上是Python函數(shù),可以為已存在的對(duì)象添加額外的功能,同時(shí)裝飾器還可以抽離出與函數(shù)無關(guān)的重用代碼。具體應(yīng)用場(chǎng)景如:插入日志、性能測(cè)試、事務(wù)處理、緩存、權(quán)限校驗(yàn)等。

換言之

裝飾器不能影響原函數(shù)的功能,裝飾器是獨(dú)立出來的函數(shù)。誰調(diào)用它,誰就可以使用它的功能。

二.舉個(gè)栗子

add的功能是計(jì)算x和y的值,我們稱作功能函數(shù)。logger的作業(yè)是在執(zhí)行add函數(shù)的同時(shí)再打印了其他的信息,這部分的作為add的功能增強(qiáng),我們稱為裝飾。在logger里我們可以加入其他類似的功能函數(shù),也能包裝它,可以進(jìn)行復(fù)用。

1.引子

#功能函數(shù)def add(x,y): return x+y#裝飾函數(shù)def logger(fn): print(’frist’) x = fn(4,5) print(’second’) return x print(logger(add))#把函數(shù)add傳給logger ,return x+y#print(’frist’)#print(’secend’)# x = fn(4,5) ==> x = 4 y= 5 x= 4+5 = 9 #return 9

fristsecond9

2.提取參數(shù)

x,y的參數(shù)都放在logger函數(shù)內(nèi)部了,影響函數(shù)的靈活性,此處我們可以提取出來。

def add(x,y): return x + ydef logger(fn,*args,**kwargs): print(’frist’) x = fn(*args,**kwargs) print(’second’) return xprint(logger(add,1,y=11))

fristsecond12

3.柯里化

def add(x,y): return x + ydef logger(fn): def wrapper(*args,**kwargs): print(’begin’) x = fn(*args,**kwargs) print(’end’) return x return wrapperprint(logger(add)(5,y=11))

beginend16

懵逼ing

以下為個(gè)人理解,左邊為非柯里化函數(shù),右邊是柯里化函數(shù)。

Python學(xué)習(xí)筆記之裝飾器

柯里化函數(shù)

前面說過柯里化的定義,本來可以一次傳入兩個(gè)參數(shù),柯里化之后。只需要傳入一個(gè)函數(shù)了。。左邊傳入add 和 兩個(gè)參數(shù)。右邊的logger(add)是一個(gè)函數(shù),只需要傳入兩個(gè)參數(shù)。logger(add)是個(gè)整體,結(jié)合成一個(gè)函數(shù)。當(dāng)然這樣寫,我們看函數(shù)主題的部分也是不一樣的。函數(shù)的基礎(chǔ)中說過,函數(shù)的傳參必須和函數(shù)參數(shù)的定義一致。重點(diǎn)分析右邊函數(shù)(柯里化)。參數(shù)部分:參數(shù)傳入的方式,logger函數(shù)需要傳入個(gè)fn,fu的返回值是wrapper函數(shù),wrapper函數(shù)的參數(shù)是(*args,**kwargs)所以此次就需要分兩次傳入?yún)?shù)。第一次傳入fn,再次傳入wrapper函數(shù)需要的參數(shù)。所以就出現(xiàn)了最下邊的調(diào)用方式。print(logger(add)(5,y=50))。

返回值部分:右側(cè)的logger函數(shù)是個(gè)嵌套函數(shù),logger的返回值是wrapper,內(nèi)層的wrapper函數(shù)返回值是x,x = fn(*args,**kwargs)。fn函數(shù)是最后調(diào)用時(shí)候傳入的add函數(shù)。

懵逼 X 2。。。。

def add(x,y): return x + ydef logger(fn,*args,**kwargs): def logger(fn): #參數(shù)剝離 def newfunction(*args,**kwargs): #新定義一個(gè)函數(shù),logger函數(shù)返回也是這個(gè)函數(shù)名字 print(’frist’) print(’frist’) x = fn(*args,**kwargs) == > x = fn(*args,**kwargs) print(’second’) print(’second’) return xreturn x return newfunctionprint(logger(add,1,y=11)) print(logger(add)(5,y=11)) #兩次傳入?yún)?shù)

效果如下:

def add(x,y): return x + ydef logger(fn): #參數(shù)剝離 def newfunction(*args,**kwargs): #新定義一個(gè)函數(shù),logger函數(shù)返回也是這個(gè)函數(shù)名字 print(’frist’) x = fn(*args,**kwargs) print(’second’) return x return newfunctionprint(logger(add)(5,y=11)) #兩次傳入?yún)?shù)

fristsecond16

繼續(xù)懵逼的話就這樣用吧。。。用多了就悟道了。。

4.裝飾器語法糖

#再次變形。。。def add(x,y): return x + ydef logger(fn): def wrapper(*args,**kwargs): print(’begin’) x = fn(*args,**kwargs) print(’end’) return x return wrapper##調(diào)用方法1:print(logger(add)(x=1111,y=1))##調(diào)用方法2:add = logger(add)print(add(x=11,y=3))##調(diào)用方法3: python給我們的語法糖 @logger # 說明下邊的函數(shù),add 其實(shí)是 add = logger(add)def add(x,y): return x + yprint(add(45,40))

beginend1112beginend14beginend85

三.復(fù)雜的栗子

import datetimeimport time def logger(fn): def warp(*arges,**kwarges): print('arges={},kwarges={}'.format(arges,kwarges)) #打印函數(shù)的兩個(gè)參數(shù) start = datetime.datetime.now() #獲取函數(shù)運(yùn)行的開始時(shí)間 ret = fn(*arges,**kwarges) #傳入兩個(gè)參數(shù),調(diào)用add函數(shù) 此處有個(gè)return的值,需要一層一層的返回出去 duratime = datetime.datetime.now() - start #獲得函數(shù)的運(yùn)行時(shí)間 print('function {} took {}s'.format(fn.__name__,duratime.total_seconds())) #打印函數(shù)的運(yùn)行時(shí)間 return ret #返回fn的結(jié)果 ,fn = x+y ==> 返回x+y的值。 x = 4 y= 11 ==> return 11 return warp #返回warp的 return ==> ret 的return ==> return 11 函數(shù)的最終結(jié)果為11 @loggerdef add(x,y): print('oooooook') time.sleep(1.5) return x+yprint(add(4,y=11))#如果充分理解了每個(gè)小部件,這個(gè)簡(jiǎn)單的完整版本也是很好理解的了。#1,logger是個(gè)裝飾器,而且使用了柯里化技術(shù)#2,add 傳參給logger的fn 形參,add(4,y=5)的兩個(gè)參數(shù)傳入給warp函數(shù)的兩個(gè)形參##

arges=(4,),kwarges={’y’: 11}oooooookfunction add took 1.5017s15

再次翻譯

import datetimeimport time #####################################裝飾開始############################################def logger(fn): #拿到函數(shù)名稱 def warp(*arges,**kwarges): #拿到函數(shù)帶過來的參數(shù)開始裝飾 print('arges={},kwarges={}'.format(arges,kwarges)) #來試試打印兩個(gè)參數(shù) start = datetime.datetime.now() # ret = fn(*arges,**kwarges) # 此處調(diào)用add函數(shù)。開始執(zhí)行函數(shù),發(fā)現(xiàn)return語句。。ret的結(jié)果就是return。 duratime = datetime.datetime.now() - start # print('function {} took {}s'.format(fn.__name__,duratime.total_seconds())) return ret #加工完成開始返回。warp的返回值是ret ,ret的返回值是 add函數(shù)的執(zhí)行結(jié)果(原函數(shù)的功能完整的保留了) return warp # logger的返回結(jié)果是warp,warp的返回值是ret ,ret的返回值是 add函數(shù)的執(zhí)行結(jié)果(原函數(shù)的功能完整的保留了) #####################################裝飾完成############################################@logger #裝飾工廠######add是需要被裝飾的函數(shù),當(dāng)你有這個(gè)想法的事情,其實(shí)事情已經(jīng)開始發(fā)生了。def add(x,y): # 此時(shí)add = logger(add) 此處前面的@logger標(biāo)記就是想要讓logger裝飾器像一個(gè)工廠一樣對(duì)add函數(shù)進(jìn)行加工。 print('oooooook') time.sleep(1.5) return x+yprint(add(4,y=11))

arges=(4,),kwarges={’y’: 11}oooooookfunction add took 1.501604s15

四.帶參裝飾器

1. 文檔字符串

我們約定,在python函數(shù)的第一行需要對(duì)函數(shù)進(jìn)行說明,使用三引號(hào)表示。如果是英文說明,慣例首字母大寫,第一行寫概述,空一行,第三行寫詳細(xì)描述。如果函數(shù)中有文檔字符串,默認(rèn)會(huì)放在函數(shù)的doc屬性中,可以直接訪問。

def add(x,y): '''This is a function of addition''' a = x+y return x + yprint('function name is {}function doc = {}'.format(add.__name__, add.__doc__))print(help(add))function name is addfunction doc = This is a function of additionHelp on function add in module __main__:add(x, y) This is a function of additionNone

2. 前面裝飾器的副作用

前面裝飾器基本上已經(jīng)可以完成對(duì)函數(shù)進(jìn)行加強(qiáng)的功能了,但是還有些瑕疵。比如原來函數(shù)的原屬性已經(jīng)被替換為裝飾器的屬性了。如下:

def add(x,y): return x + ydef logger(fn): 'This is logger doc' def wrapper(*args,**kwargs): 'This is wrapper doc' print(’begin’) x = fn(*args,**kwargs) print(’end’) return x return wrapper@logger # add = logger(add)def add(x,y): 'This is add doc ' print('name = {}doc = {}'.format(add.__name__,add.__doc__)) return x + yprint(add(45,40))#可以看出來add被裝飾出來的函數(shù)(新的add)的屬性已經(jīng)全部改變了。

beginname = wrapperdoc = This is wrapper docend85

3. 解決方案一

三個(gè)函數(shù):

第一個(gè):copy原函數(shù)的屬性 copy_properties第二個(gè):裝飾器 logger第三個(gè):功能函數(shù) add

def copy_properties(src, dst): # 把src的相關(guān)屬性賦值給dst (fn,wrap) dst.__name__ = src.__name__ dst.__doc__ = src.__doc__def logger(fn): '''’This is a function of logger’''' def wrap(*arges,**kwarges): # '''’This is a function of wrap’''' print(’<>-<>-<>-<>-<>-<>-<>-<>-<>-<>-<>-<>-<>-<>-<>-<>-<>-<>’) x = fn(*arges,**kwarges) #print('name={}doc={}'.format(add.__name__,add.__doc__)) print(’<>-<>-<>-<>-<>-<>-<>-<>-<>-<>-<>-<>-<>-<>-<>-<>-<>-<>’) return x copy_properties(fn,wrap) #思考1:為什么放在這個(gè)位置調(diào)用 return wrap@loggerdef add(x,y): '''’This is a function of add’''' print('name={}doc={}'.format(add.__name__,add.__doc__)) return x+yprint(add(4,6))

<>-<>-<>-<>-<>-<>-<>-<>-<>-<>-<>-<>-<>-<>-<>-<>-<>-<>name=adddoc=’This is a function of add’<>-<>-<>-<>-<>-<>-<>-<>-<>-<>-<>-<>-<>-<>-<>-<>-<>-<>10

4. 解決方案二

但凡使用裝飾器都會(huì)出現(xiàn)屬性的這個(gè)問題,為什么不把copy_properties也做成裝飾器呢?

三個(gè)函數(shù):

第一個(gè):copy原函數(shù)的裝飾器 copy_properties1第二個(gè):裝飾器 logger第三個(gè):功能函數(shù) add

def copy_properties(src, dst): # 把src的相關(guān)屬性賦值給dst (fn,wrap) dst.__name__ = src.__name__ dst.__doc__ = src.__doc__#利用前面的知識(shí)我們可以對(duì)copy_properties輕松進(jìn)行變形def copy_properties1(src): # 把src的相關(guān)屬性賦值給dst (fn,wrap) def _copy(dst): dst.__name__ = src.__name__ dst.__doc__ = src.__doc__ return dst return _copy

帶參裝飾器:

def logger(fn): '''’This is a function of logger’''' @copy_properties1(fn) #wrap = copy_properties(fn)(wrap) #== > 柯里化 兩次傳入?yún)?shù) src = fn , dst = wrap 新的wrap函數(shù)的屬性已經(jīng)替換為原函數(shù)的。 def wrap(*arges,**kwarges): #wrap = copy_properties(fn)(wrap)(*arges,**kwarges) '''’This is a function of wrap’''' print(’>->->->->->->->->->->->->->->->->->->->->->->->->->’) x = fn(*arges,**kwarges) print(’<-<-<-<-<-<-<-<-<-<-<-<-<-<-<-<-<-<-<-<-<-<-<-<-<-<’) return x return wrap@logger #add =logger(add)def add(x,y): '''’This is a function of add’''' print('name={}doc={}'.format(add.__name__,add.__doc__)) return x+yprint(add(4,11))

以上就是詳解Python 裝飾器的詳細(xì)內(nèi)容,更多關(guān)于Python 裝飾器的資料請(qǐng)關(guān)注好吧啦網(wǎng)其它相關(guān)文章!

標(biāo)簽: Python 編程
相關(guān)文章:
主站蜘蛛池模板: 国产成人综合亚洲欧美在 | 亚洲综合一区二区不卡 | 99国产精品久久久久久久... | 日韩一区视频在线 | 美国免费高清一级毛片 | 欧美特黄高清免费观看的 | 成人三级精品视频在线观看 | 中文字幕在线免费观看视频 | 国产日韩亚洲欧美 | a级网站在线观看 | 日本免费毛片 | 欧美日韩国产高清一区二区三区 | 亚洲国产精品a一区二区三区 | 香蕉成人| 在线视频 亚洲 | 亚洲综合在线视频 | 特级毛片 | 欧美性色欧美a在线播放 | 男人天堂怡红院 | 成人欧美视频在线看免费 | 美国毛片一级视频在线aa | 日本韩国欧美在线观看 | 韩国一级特黄清高免费大片 | 高级毛片 | 精品久久久久不卡无毒 | 亚洲欧美专区精品久久 | xxxxx日本59| 中国女人18xnxx视频 | 成人永久福利在线观看不卡 | 午夜宅男宅女看在线观看 | 国产精品久久久久亚洲 | www.自拍| 成人欧美一区二区三区在线观看 | 国产毛片久久精品 | 日韩在线观看一区 | 在线观看欧美亚洲日本专区 | 久久er热这里只有精品23 | 福利一二三区 | 毛片韩国 | 理论在线看 | 在线午夜影院 |