
1. 裝飾器的概念類比所謂的裝飾器, 其實(shí)就是一種概念上的比喻說(shuō)法。這種說(shuō)法認(rèn)為。給函數(shù)這個(gè)對(duì)象。穿上了一件。額外的外衣。我們來(lái)做一個(gè)假設(shè)。想象你手頭有一個(gè)函數(shù)存在。它就像一個(gè)自然人一樣。這個(gè)人具備完成特定任務(wù)的能力。舉個(gè)例子來(lái)說(shuō)。這個(gè)人可以執(zhí)行計(jì)算兩個(gè)數(shù)值之和的操作。那么。裝飾器到底是干什么的。它的作用就像是給上述提到的人。強(qiáng)行添加一些輔助性的功能出來(lái)。比如在正式執(zhí)行加法運(yùn)算之前。先對(duì)傳入的參數(shù)進(jìn)行合規(guī)性篩查。另外。也可能在運(yùn)算結(jié)束以后。順手把所用時(shí)間記錄下來(lái)。從另一個(gè)角度來(lái)講, 那個(gè)裝飾器呀, 它是跟手機(jī)上的那個(gè)保護(hù)殼差不多的一個(gè)東西, 手機(jī)本身, 它就是一個(gè)函數(shù), 它有那些基本的功能存在, 比如說(shuō)打電話和發(fā)短信這些東西都是它的功能, 那個(gè)保護(hù)殼作為裝飾器, 它可以給這部手機(jī)增加一些其他的新功能的, 像是防水啊防摔啊這種新功能的存在是不去改變手機(jī)本身所具備的那些打電話以及發(fā)短信的基本的功能的, 不過(guò)它確實(shí)是可以增強(qiáng)手機(jī)的那個(gè)整體的性能的。2. 簡(jiǎn)單的裝飾器示例代碼解釋首先, 我們要去看一下一個(gè)最基礎(chǔ)的用來(lái)做裝飾的結(jié)構(gòu)是個(gè)什么樣子的。pythondef decorator_function(func):def wrapper():print(在函數(shù)執(zhí)行前做一些事情)func()print(在函數(shù)執(zhí)行后做一些事情)return wrapper在這里我們定義了一個(gè)名為空的函數(shù), 這個(gè)函數(shù)的名字是空白的, 它接收到了一個(gè)叫做func的作為參數(shù), 并且把這個(gè)叫func的當(dāng)作是這個(gè)函數(shù)自己的參數(shù)來(lái)處理, 而這個(gè)名稱為空白的這個(gè)函數(shù)部分呢, 我們就把它給稱為是我們的那個(gè)裝飾器。然后在裝飾器里面定義了一個(gè)新函數(shù), 這個(gè)新函數(shù)就像是為原來(lái)的那個(gè) func 函數(shù)穿上了一件衣服。當(dāng)調(diào)用那個(gè)被修飾的函數(shù)的時(shí)候, 程序會(huì)先執(zhí)行打印出在函數(shù)執(zhí)行前做一些事情的這句代碼, 這個(gè)操作就是代表著向原本函數(shù)的流程里面添加了一個(gè)前置的動(dòng)作或者說(shuō)是額外加的功能, 緊接著再去運(yùn)行func()這個(gè)原來(lái)的核心邏輯, 等到里面的主體部分都處理完了, 最后再去執(zhí)行打印出在函數(shù)執(zhí)行后做一些事情的這一句代碼, 這步就是在說(shuō)原來(lái)函數(shù)跑完之后還要加上一個(gè)后置的處理環(huán)節(jié), 整個(gè)這一套流程就這么按順序地給過(guò)了一遍, 先事前準(zhǔn)備, 再處理核心事情, 最后是事后收尾。等到最后, 裝飾器返回函數(shù)這個(gè)對(duì)象。我們假設(shè)一下, 我們這里存在一個(gè)函數(shù), 這個(gè)函數(shù)的復(fù)雜度是比較簡(jiǎn)單的。pythondef say_hello():print(Hello!)關(guān)于如何使用裝飾器來(lái)對(duì)這個(gè)函數(shù)進(jìn)行裝飾操作, 我們可以采取下面的這一種做法方式來(lái)完成任務(wù)。pythondecorated_say_hello decorator_function(say_hello)decorated_say_hello()首先第一步是把這個(gè)函數(shù)傳遞給裝飾器。然后返回的那個(gè)函數(shù)會(huì)被賦值給。最后再去調(diào)用()。這么一調(diào)用就會(huì)執(zhí)行函數(shù)。這就實(shí)現(xiàn)了在函數(shù)執(zhí)行之前和執(zhí)行之后去添加一些額外的功能。3. 語(yǔ)法糖形式的裝飾器解釋在實(shí)際使用的過(guò)程中, 還有一種更為簡(jiǎn)潔的方式可以來(lái)使用裝飾器, 這種方式我們給它取了一個(gè)名字, 叫作語(yǔ)法糖。依據(jù)上面所展示的代碼內(nèi)容, 我們可以對(duì)其進(jìn)行如下的改寫操作:pythondecorator_functiondef say_hello():print(Hello!)這種使用了符號(hào)的寫法, 其意義其實(shí)就是等同于 ()這樣的形式。它可以讓代碼看上去更加簡(jiǎn)潔一些。同時(shí), 它也更符合現(xiàn)在大家習(xí)慣了的編程方式。4. 裝飾器的實(shí)際用途舉例日志記錄假設(shè)說(shuō)你現(xiàn)在有一個(gè)函數(shù), 這個(gè)函數(shù)是用來(lái)處理用戶的訂單情況的, 你想要把這每一次去調(diào)用這個(gè)函數(shù)的具體時(shí)間記錄下來(lái), 并且還想把這個(gè)函數(shù)里面的參數(shù)信息等東西也都保存下來(lái)。pythonimport timedef log_decorator(func):def wrapper(*args, kwargs):start_time time.time()print(f開始調(diào)用函數(shù) {func.__name__}參數(shù)為{args}和{kwargs})result func(*args, kwargs)end_time time.time()print(f函數(shù) {func.__name__} 執(zhí)行完成耗時(shí){(end_time start_time)}秒)return resultreturn wrapperlog_decoratordef process_order(order_id, product_name):print(f正在處理訂單 {order_id}產(chǎn)品為{product_name})# 模擬訂單處理時(shí)間time.sleep(2)return 訂單處理成功在這里, 裝飾器這個(gè)東西是可以用來(lái)記錄函數(shù)在調(diào)用的時(shí)候所花費(fèi)的時(shí)間以及所使用的參數(shù)等等相關(guān)信息的。并且, 當(dāng)去調(diào)用特定的這個(gè)函數(shù)的時(shí)候, 就會(huì)自動(dòng)地去把裝飾器里面已經(jīng)寫好的那些代碼給執(zhí)行起來(lái)。這樣做呢, 就是在函數(shù)正式被執(zhí)行之前和之后這兩個(gè)階段里, 額外地加上一些專門用于記錄日志的功能操作。權(quán)限驗(yàn)證如果你手頭有一個(gè)用于獲取用戶敏感信息的網(wǎng)頁(yè)應(yīng)用后端函數(shù), 那么你可能就需要去驗(yàn)證這個(gè)用戶到底有沒有權(quán)限進(jìn)行訪問(wèn)。pythondef permission_check_decorator(func):def wrapper(user):if user.has_permission():return func(user)else:print(用戶沒有權(quán)限訪問(wèn)此功能)return wrapperclass User:def __init__(self, has_permission):self.has_permission has_permissionpermission_check_decoratordef get_user_info(user):print(獲取用戶信息)return 用戶的詳細(xì)信息在這個(gè)例子中裝飾器會(huì)檢查用戶對(duì)象user是否有訪問(wèn)權(quán)限這一點(diǎn)是現(xiàn)在人們能直接看懂的普通話書面語(yǔ), 如果有這個(gè)權(quán)限的話就執(zhí)行相關(guān)函數(shù)來(lái)獲取用戶信息, 如果沒有這個(gè)權(quán)限的話就打印提示信息, 這樣操作的目的就是為了通過(guò)裝飾器這一手段方便地給函數(shù)添加權(quán)限驗(yàn)證的功能, 每個(gè)詞都要是現(xiàn)在常用的, 長(zhǎng)句被切斷成了逗號(hào)分句。