摘要:那么,這個(gè)裝飾器要怎么定義呢我們來(lái)看一下。當(dāng)然了,如果大家在網(wǎng)絡(luò)上搜索,關(guān)于如何定義裝飾器,看到的是一個(gè)更加規(guī)范的版本。在當(dāng)中,調(diào)用原函數(shù)時(shí)又,即把輸入的元祖解包再傳入。
我們?cè)诰幊踢^(guò)程中,常常會(huì)遇到這種需求:
比如,我想開(kāi)發(fā)一款計(jì)算器,我已經(jīng)寫(xiě)好了一堆函數(shù),用于執(zhí)行各種計(jì)算,那么我們需要在執(zhí)行各種計(jì)算函數(shù)前,首先對(duì)輸入的數(shù)據(jù)進(jìn)行檢查,確保他們必須得是數(shù)值才允許執(zhí)行函數(shù),而不能是字符串;
又如,我想編寫(xiě)一個(gè)用于計(jì)算三角形周長(zhǎng)、面積、某個(gè)角角度的模塊,已經(jīng)寫(xiě)好幾個(gè)函數(shù)用于計(jì)算,那么,在執(zhí)行計(jì)算前,首先要確保輸入的三條邊長(zhǎng)能夠構(gòu)成三角形,再進(jìn)行計(jì)算才有意義;
再比如,我想開(kāi)發(fā)某款網(wǎng)絡(luò)應(yīng)用,寫(xiě)了一些函數(shù)用于實(shí)現(xiàn)用戶的某些操作,那么,得要先檢查確認(rèn)該用戶已經(jīng)登錄了,才允許執(zhí)行這些操作。
這些需求,歸納起來(lái),就是,在執(zhí)行主函數(shù)之前,常常要先執(zhí)行某個(gè)預(yù)函數(shù),進(jìn)行一些校驗(yàn)之類的操作。
這類需求是非常常見(jiàn)的,也是保證程序完整性、健壯性的重要舉措。所以,怎么做才比較簡(jiǎn)單呢?
你會(huì)說(shuō),這很簡(jiǎn)單啊,在每個(gè)函數(shù)里面寫(xiě)上if語(yǔ)句不就得了。就拿那個(gè)計(jì)算器而言,如果我們要寫(xiě)加減乘除,我們可以這樣:
def plus(a,b): if type(a)==type(0) and type(b)==type(0): #假設(shè)該計(jì)算器只能計(jì)算整數(shù),如果要計(jì)算小數(shù)再or type(0.0) return a+b else: print("Type must be number") #檢測(cè)到數(shù)據(jù)類型不對(duì),先輸出報(bào)警,函數(shù)值返回None return Nonedef minus(a,b): if type(a)==type(0) and type(b)==type(0): return a-b else: print("Type must be number") return Nonedef multiply(a,b): if type(a)==type(0) and type(b)==type(0): return a*b else: print("Type must be number") return Nonedef divide(a,b): if type(a)==type(0) and type(b)==type(0): return a/b else: print("Type must be number") return None
這個(gè)嘛,直接暴力。但是呢,這里只有4個(gè)函數(shù),假如你開(kāi)發(fā)的計(jì)算器有幾十幾百個(gè)函數(shù),每個(gè)函數(shù)都要套上if語(yǔ)句,這不得麻煩死了,不煩死也啰嗦死了。
所以怎么弄簡(jiǎn)單一點(diǎn)呢?聰明的你肯定想到了,我們可以把那個(gè)判斷if也多帶帶定義一個(gè)函數(shù),然后把計(jì)算用的函數(shù)套在里面,就像這樣:
def check(a,b,func): #定義檢查函數(shù),變量為待檢測(cè)參數(shù)a,b和檢測(cè)通過(guò)后執(zhí)行的函數(shù)func if type(a)==type(0) and type(b)==type(0): return func(a,b) else: print("Type must be number") return Nonedef plus(a,b): return a+bdef minus(a,b): return a-b...#主程序check(1,2,plus) #計(jì)算1+2check(1,2,minus) #計(jì)算1-2check(1,2,multiply) #計(jì)算1*2check(1,2,divide) #計(jì)算1/2
這里面有一點(diǎn)一定要特別注意,主程序的check(1,2,plus) 是把plus函數(shù)本身作為變量傳遞給check,由check函數(shù)決定如何執(zhí)行plus函數(shù),此處不能寫(xiě)成check(1,2,plus(1,2)),plus不能帶參數(shù)和括號(hào),不是執(zhí)行plus()后把結(jié)果傳給check。
這么寫(xiě)程序簡(jiǎn)潔了不少,加減乘除函數(shù)只需要定義他們本身的運(yùn)算就可以了,變量檢測(cè)交給了check函數(shù)。這么寫(xiě)也是比較容易理解的。
但是對(duì)于使用該程序的用戶來(lái)說(shuō),就不是這么回事了,他們會(huì)覺(jué)得這么寫(xiě)非常難看。
為什么呢?我是要拿程序做加減乘除計(jì)算的,但我不論計(jì)算什么,每次都是在主調(diào)用check這個(gè)函數(shù)!
那有沒(méi)有什么辦法,可以既好看,又簡(jiǎn)潔呢?裝飾器就是起到了這個(gè)神奇的作用。
上面這個(gè)需求,用裝飾器可以這么寫(xiě):
def check(func): ...@checkdef plus(a,b): return a+b@checkdef minus(a,b): return a-b...#主程序plus(1,2) #計(jì)算1+2minus(1,2) #計(jì)算1-2...
先直觀感受一下,通過(guò)@check,check函數(shù)就被“注入”到了plus函數(shù)中,使得plus函數(shù)擁有了參數(shù)檢測(cè)的功能。這樣,在主程序中,若要計(jì)算加法就可直接調(diào)用plus,便可先校驗(yàn)再計(jì)算。
那么,這個(gè)裝飾器check要怎么定義呢?我們來(lái)看一下。
def check(func): #定義裝飾器check def newfunc(a,b): #定義函數(shù)模板,即如何處理func if type(a)==type(0) and type(b)==type(0): return func(a,b) else: print("Type must be number!") return None return newfunc #將處理后的func作為新函數(shù)newfunc輸出@checkdef plus(a,b): return a+b#主程序,計(jì)算1+2plus(1,2)
我們可以看到,當(dāng)裝飾器@check作用于plus函數(shù)時(shí),plus函數(shù)本身作為參數(shù)func傳入裝飾器中。在裝飾器check的定義內(nèi)部,定義了一個(gè)函數(shù)模板,描述了對(duì)輸入的func如何處理。可以看到,newfunc對(duì)func(也就是輸入的plus)套用了判斷數(shù)據(jù)類型的if語(yǔ)句,最后,再將套好的newfunc輸出,替代原來(lái)的func。這樣,此時(shí)執(zhí)行func就是在執(zhí)行newfunc,執(zhí)行plus就是在執(zhí)行套上if語(yǔ)句的新函數(shù)。
所以,通過(guò)裝飾器,添加上了判斷語(yǔ)句的新函數(shù)替換了原來(lái)的plus函數(shù),但仍通過(guò)plus這個(gè)函數(shù)名調(diào)用,所以看起來(lái)就是plus函數(shù)被“裝飾”了。
當(dāng)然了,如果大家在網(wǎng)絡(luò)上搜索,關(guān)于如何定義裝飾器,看到的是一個(gè)更加規(guī)范的版本。看起來(lái)更難理解一些,但其實(shí)是一樣的:
def checkall(func): def wrapper(*args,**kwargs): if type(args[0])==type(0) and type(args[1])==type(0): return func(*args,**kwargs) else: print("Type must be number!") return None return wrapper
模板函數(shù)一般習(xí)慣用wrapper來(lái)表示,這個(gè)沒(méi)啥,建議大家都這么寫(xiě),規(guī)范一些。
參數(shù)一般用不定長(zhǎng)的*args,**kwargs來(lái)表示,這個(gè)可能有些人就困惑了。因?yàn)楸谎b飾的函數(shù)可能有很多種,參數(shù)的個(gè)數(shù)一般也不確定。然后*args,**kwargs是什么東西?args,kwargs這兩個(gè)形參英文字母是什么無(wú)所謂可以自己定,關(guān)鍵是前面的單星號(hào)*和雙星號(hào)**。
假如我定義一個(gè)函數(shù),不能確定參數(shù)有多少個(gè),例如要對(duì)輸入的一組數(shù)字做連加操作。那么就可以定義plus(*x),當(dāng)調(diào)用該函數(shù)時(shí),若輸入多個(gè)變量plus(1,2,3),那么就會(huì)把輸入的變量組合成一個(gè)元祖x=(1,2,3)輸入。定義雙星號(hào)plus(**x)的意思是,調(diào)用該函數(shù)時(shí)若寫(xiě)出形參變量plus(a=1,b=2,c=3),那么輸入變量就會(huì)組合成字典x={a:1,b:2,c:3}傳入函數(shù)。
當(dāng)然也可以反向操作,定義函數(shù)的時(shí)候參數(shù)個(gè)數(shù)是明確的plus(a,b,c),那么調(diào)用該函數(shù)時(shí),加上星號(hào)plus(*(1,2,3)),就是對(duì)輸入元祖(1,2,3)執(zhí)行炸開(kāi)操作,轉(zhuǎn)換為plus(1,2,3)輸入。
裝飾器里這么寫(xiě)有什么用呢?我們仔細(xì)觀察一下我們之前寫(xiě)的newfunc(a,b),那就意味著,指明了新函數(shù)有兩個(gè)參數(shù)a,b,假如被裝飾的原函數(shù)有三個(gè)參數(shù)怎么辦呢?不就沒(méi)用了嗎?
我們來(lái)看別人寫(xiě)的,定義時(shí)用了wrapper(*args,**kwargs),即不管有多少個(gè)參數(shù),打包輸入wrapper。在wrapper當(dāng)中,調(diào)用原函數(shù)時(shí)又func(*args,**kwargs),即把輸入的元祖解包再傳入func。這么一打包一解包,雖然看起來(lái)啥都沒(méi)干,但確適應(yīng)了函數(shù)參數(shù)不確定的情況,使得該裝飾器可以裝飾多種參數(shù)數(shù)量不同的函數(shù)。
就先這樣吧。
歡迎轉(zhuǎn)載、收藏、有所收獲點(diǎn)贊支持一下!
目前開(kāi)通了技術(shù)交流群,群友已超過(guò)2000人,添加時(shí)最好的備注方式為:來(lái)源+興趣方向,方便找到志同道合的朋友
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://specialneedsforspecialkids.com/yun/124520.html
摘要:一引用書(shū)流暢的書(shū)二基本概念問(wèn)題裝飾器是什么解答嚴(yán)格來(lái)說(shuō),裝飾器只是語(yǔ)法糖,裝飾器是可調(diào)用的對(duì)象,可以像常規(guī)的可調(diào)用對(duì)象那樣調(diào)用,特殊的地方是裝飾器的參數(shù)是一個(gè)函數(shù)問(wèn)題裝飾器有什么特性解答裝飾器有個(gè)特性,一是可以把被裝飾的函數(shù)替換成其他函數(shù), 一, 引用 [書(shū)] 流暢的Python [書(shū)] Effective Python 二, 基本概念 showImg(https://segme...
摘要:今天就結(jié)合最近的世界杯帶大家理解下裝飾器。而德國(guó)是上屆的冠軍,又是這屆奪冠熱門。裝飾器的存在是為了適用兩個(gè)場(chǎng)景,一個(gè)是增強(qiáng)被裝飾函數(shù)的行為,另一個(gè)是代碼重用。在利用語(yǔ)法糖,簡(jiǎn)化賦值操作。行為良好的裝飾器可以重用,以減少代碼量。 Python 裝飾器是在面試過(guò)程高頻被問(wèn)到的問(wèn)題,裝飾器也是一個(gè)非常好用的特性,熟練掌握裝飾器會(huì)讓你的編程思路更加寬廣,程序也更加 pythonic。 show...
摘要:我們以測(cè)量函數(shù)運(yùn)行時(shí)間為例來(lái)講一講裝飾器的運(yùn)行原理。三更加通用的裝飾器前面兩部分講了裝飾器的原理,這一部分就講講要寫(xiě)出一個(gè)通用的裝飾器需要注意的問(wèn)題。首先就是參數(shù)的問(wèn)題,裝飾器返回的函數(shù)不是原來(lái)的函數(shù),函數(shù)的簽名也就和原來(lái)的函數(shù)簽名不一樣。 一、最簡(jiǎn)單的裝飾器 裝飾器是python中很基礎(chǔ)也很實(shí)用的一個(gè)特性。通過(guò)裝飾器我們可以很方便地為一些函數(shù)添加相同的功能。我們以測(cè)量函數(shù)運(yùn)行時(shí)間為例...
摘要:使用類裝飾器,優(yōu)點(diǎn)是靈活性大,高內(nèi)聚,封裝性。不過(guò)不用擔(dān)心,有,本身也是一個(gè)裝飾器,它的作用就是把原函數(shù)的元信息拷貝到裝飾器函數(shù)中,使得裝飾器函數(shù)也有和原函數(shù)一樣的元信息。 showImg(https://segmentfault.com/img/bVbrFWb?w=742&h=484);Python的裝飾器(decorator)是一個(gè)很棒的機(jī)制,也是熟練運(yùn)用Python的必殺技之一。...
摘要:裝飾器是可調(diào)用的對(duì)象,其參數(shù)是另一個(gè)函數(shù)被裝飾的函數(shù)。第二大特性是,裝飾器在加載模塊時(shí)立即執(zhí)行。另一個(gè)常見(jiàn)的裝飾器是,它的作用是協(xié)助構(gòu)建行為良好的裝飾器。 裝飾器是可調(diào)用的對(duì)象,其參數(shù)是另一個(gè)函數(shù)(被裝飾的函數(shù))。 裝飾器基礎(chǔ)知識(shí) 首先看一下這段代碼 def deco(fn): print I am %s! % fn.__name__ @deco def func(): ...
閱讀 1031·2021-11-23 09:51
閱讀 2352·2021-10-08 10:22
閱讀 2567·2021-09-29 09:35
閱讀 862·2021-09-22 15:20
閱讀 2864·2019-08-30 15:53
閱讀 2417·2019-08-30 13:55
閱讀 1106·2019-08-29 17:27
閱讀 2874·2019-08-29 17:26