亚洲国产日韩欧美一区二区三区,精品亚洲国产成人av在线,国产99视频精品免视看7,99国产精品久久久久久久成人热,欧美日韩亚洲国产综合乱

裝飾器

上一篇文章將透過解決一個(gè)需求問題來了解了閉包,本文也將一樣,透過慢慢演變一個(gè)需求,一步一步來了解 Python 裝飾器。

首先有這麼一個(gè)輸出員工打卡資訊的函數(shù):

def punch():
    print('昵稱:兩點(diǎn)水  部門:做鴨事業(yè)部 上班打卡成功')
punch()

輸出的結(jié)果如下:

昵稱:兩點(diǎn)水  部門:做鴨事業(yè)部 上班打卡成功

然後,產(chǎn)品回饋,不行啊,怎麼上班打卡沒有具體的日期,加上打卡的具體日期吧,這應(yīng)該很簡單,分分鐘解決囉。好吧,那就直接添加列印日期的程式碼吧,如下:

import time
def punch():
    print(time.strftime('%Y-%m-%d', time.localtime(time.time())))
    print('昵稱:兩點(diǎn)水  部門:做鴨事業(yè)部 上班打卡成功')
punch()

輸出結(jié)果如下:

2018-01-09
昵稱:兩點(diǎn)水  部門:做鴨事業(yè)部 上班打卡成功

這樣改是可以,可是這樣改是改變了函數(shù)的功能結(jié)構(gòu)的,本身這個(gè)函數(shù)定義的時(shí)候就是列印某個(gè)員工的資訊和提示打卡成功,現(xiàn)在增加列印日期的程式碼,可能會造成很多程式碼重複的問題。例如,還有一個(gè)地方只需要列印員工資訊和打卡成功就行了,不需要日期,那麼你又要重寫一個(gè)函數(shù)嗎?而且列印目前日期的這個(gè)功能方法是經(jīng)常使用的,是可以作為公共函數(shù)給各個(gè)模組方法呼叫的。當(dāng)然,這都是作為一個(gè)整體項(xiàng)目來考慮的。

既然是這樣,我們可以使用函數(shù)式程式設(shè)計(jì)來修改這部分的程式碼。因?yàn)橥高^先前的學(xué)習(xí),我們知道Python 函數(shù)有兩個(gè)特點(diǎn),函數(shù)也是一個(gè)對象,而且函數(shù)裡可以巢狀函數(shù),那麼修改一下程式碼變成下面這個(gè)樣子:

import time
def punch():
    print('昵稱:兩點(diǎn)水  部門:做鴨事業(yè)部 上班打卡成功')
def add_time(func):
    print(time.strftime('%Y-%m-%d', time.localtime(time.time())))
    func()
add_time(punch)

輸出結(jié)果:

2018-01-09
昵稱:兩點(diǎn)水  部門:做鴨事業(yè)部 上班打卡成功

這樣是不是發(fā)現(xiàn),這樣子就沒有改動punch 方法,而且任何需要用到打印當(dāng)前日期的函數(shù)都可以把函數(shù)傳進(jìn)add_time 就可以了,就比如這樣:

import time
def punch():
    print('昵稱:兩點(diǎn)水  部門:做鴨事業(yè)部 上班打卡成功')
def add_time(func):
    print(time.strftime('%Y-%m-%d', time.localtime(time.time())))
    func()
def holiday():
    print('天氣太冷,今天放假')
add_time(punch)
add_time(holiday)

列印結(jié)果:

2018-01-09
昵稱:兩點(diǎn)水  部門:做鴨事業(yè)部 上班打卡成功
2018-01-09
天氣太冷,今天放假

使用函數(shù)程式設(shè)計(jì)是不是很方便,但是,我們每次呼叫的時(shí)候,我們都必須把原來的函數(shù)當(dāng)作參數(shù)傳遞進(jìn)去,還能不能有更好的實(shí)作方式呢?有的,就是本文要介紹的裝飾器,因?yàn)檠b飾器的寫法其實(shí)跟閉包是差不多的,不過沒有了自由變量,那麼這裡直接給出上面那段代碼的裝飾器寫法,來對比一下,裝飾器的寫法和函數(shù)式程式設(shè)計(jì)有啥不同。

import time
def decorator(func):
    def punch():
        print(time.strftime('%Y-%m-%d', time.localtime(time.time())))
        func()
    return punch
def punch():
    print('昵稱:兩點(diǎn)水  部門:做鴨事業(yè)部 上班打卡成功')
f = decorator(punch)
f()

輸出的結(jié)果:

2018-01-09
昵稱:兩點(diǎn)水  部門:做鴨事業(yè)部 上班打卡成功

透過程式碼,能知道裝飾器函數(shù)一般做這三件事:

接收一個(gè)函數(shù)作為參數(shù)

巢狀一個(gè)包裝函數(shù), 包裝函數(shù)會接收原函數(shù)的相同參數(shù),並執(zhí)行原函數(shù),也會執(zhí)行附加功能

返回巢狀函數(shù)

可是,認(rèn)真一看這程式碼,這裝飾器的寫法怎麼比函數(shù)式程式設(shè)計(jì)還麻煩。而且看起來比較複雜,甚至有點(diǎn)多此一舉的感覺。

那是因?yàn)槲覀冞€沒用到裝飾器的「語法糖」 ,我們看上面的程式碼可以知道, Python 在引入裝飾器(Decorator) 的時(shí)候,沒有引入任何新的語法特性,都是基於函數(shù)的語法特性。這也就說明了裝飾器不是 Python 特有的,而是每個(gè)語言通用的一種程式設(shè)計(jì)想法。只不過Python 設(shè)計(jì)出了@ 語法糖,讓定義裝飾器,把裝飾器調(diào)用原函數(shù)再把結(jié)果賦值為原函數(shù)的對象名的過程變得更加簡單,方便,易操作,所以Python 裝飾器的核心可以說就是它的語法糖。

那麼要怎麼使用它的語法糖呢?很簡單,根據(jù)上面的寫法寫完裝飾函數(shù)後,直接在原來的函數(shù)上加上 @ 和裝飾器的函數(shù)名稱。如下:

import time
def decorator(func):
    def punch():
        print(time.strftime('%Y-%m-%d', time.localtime(time.time())))
        func()
    return punch
@decorator
def punch():
    print('昵稱:兩點(diǎn)水  部門:做鴨事業(yè)部 上班打卡成功')
punch()

輸出結(jié)果:

2018-01-09
昵稱:兩點(diǎn)水  部門:做鴨事業(yè)部 上班打卡成功

那麼這就很方便了,方便在我們的呼叫上,例如例子中的,使用了裝飾器後,直接在原本的函數(shù)加上裝飾器的語法糖就可以了,本函數(shù)也無虛任何改變,呼叫的地方也不需修改。

不過這裡一直有個(gè)問題,就是輸出打卡訊息的是固定的,那我們需要透過參數(shù)來傳遞,裝飾器該怎麼寫呢?裝飾器中的函數(shù)可以使用*args 可變參數(shù),可是僅使用*args 是無法完全包含所有參數(shù)的情況,例如關(guān)鍵字參數(shù)就不能了,為了能相容關(guān)鍵字參數(shù),我們還需要加上**kwargs 。

因此,裝飾器的最終形式可以寫成這樣:

import time
def decorator(func):
    def punch(*args, **kwargs):
        print(time.strftime('%Y-%m-%d', time.localtime(time.time())))
        func(*args, **kwargs)
    return punch
@decorator
def punch(name, department):
    print('昵稱:{0}  部門:{1} 上班打卡成功'.format(name, department))
@decorator
def print_args(reason, **kwargs):
    print(reason)
    print(kwargs)
punch('兩點(diǎn)水', '做鴨事業(yè)部')
print_args('兩點(diǎn)水', sex='男', age=99)

輸出結(jié)果如下:

2018-01-09
昵稱:兩點(diǎn)水  部門:做鴨事業(yè)部 上班打卡成功
2018-01-09
兩點(diǎn)水
{'sex': '男', 'age': 99}

至此,草根學(xué) Python 入門系列文章結(jié)束了。


繼續(xù)學(xué)習(xí)
||
提交重置程式碼