裝飾器

裝飾器一直以來都是 Python 中很有用、很經(jīng)典的一個(gè) feature滴劲,在工程中的應(yīng)用也十分廣泛攻晒,比如日志、緩存等等的任務(wù)都會(huì)用到班挖。
python中函數(shù)是一等公民鲁捏,使用非常靈活。函數(shù)可以作為參數(shù)萧芙,也可以作為返回值给梅,函數(shù)可以嵌套。

def func_closure():
    def get_message(message):
        print('Got a message: {}'.format(message))
    return get_message

send_message = func_closure()
send_message('hello world')

# 輸出
Got a message: hello world

這里双揪,函數(shù) func_closure() 的返回值是函數(shù)對象 get_message 本身动羽,之后,我們將其賦予變量 send_message盟榴,再調(diào)用 send_message(‘hello world’)曹质,最后輸出了'Got a message: hello world'。

簡單的裝飾器

def my_decorator(func):
    def wrapper():
        print('wrapper of decorator')
        func()
    return wrapper

def greet():
    print('hello world')

greet = my_decorator(greet)
greet()

# 輸出
wrapper of decorator
hello world

這是簡單裝飾器的例子,greet指向內(nèi)部函數(shù)wrapper羽德,wrapper又會(huì)調(diào)用原函數(shù)greet几莽,因此先輸出'wrapper of decorator',然后輸出'hello world'宅静。
這里的函數(shù) my_decorator() 就是一個(gè)裝飾器章蚣,它把真正需要執(zhí)行的函數(shù) greet() 包裹在其中,并且改變了它的行為姨夹,但是原函數(shù) greet() 不變纤垂。
對于裝飾器,Python中更簡單磷账、優(yōu)雅地使用方式


def my_decorator(func):
    def wrapper():
        print('wrapper of decorator')
        func()
    return wrapper

@my_decorator
def greet():
    print('hello world')

greet()

帶參數(shù)的裝飾器

def my_decorator(func): 
    def wrapper(*args, **kwargs): 
        print('wrapper of decorator') 
        func(*args, **kwargs) 
     return wrapper

args和*kwargs峭沦,表示接受任意數(shù)量和類型的參數(shù)。

自定義參數(shù)的裝飾器

其實(shí)逃糟,裝飾器還有更大程度的靈活性吼鱼。剛剛說了,裝飾器可以接受原函數(shù)任意類型和數(shù)量的參數(shù)绰咽,除此之外菇肃,它還可以接受自己定義的參數(shù)。舉個(gè)例子取募,比如我想要定義一個(gè)參數(shù)琐谤,來表示裝飾器內(nèi)部函數(shù)被執(zhí)行的次數(shù),那么就可以寫成下面這種形式:

def repeat(num):
    def my_decorator(func):
        def wrapper(*args, **kwargs):
            for i in range(num):
                print('wrapper of decorator')
                func(*args, **kwargs)
        return wrapper
    return my_decorator

@repeat(4)
def greet(message):
    print(message)

greet('hello world')

# 輸出:
wrapper of decorator
hello world
wrapper of decorator
hello world
wrapper of decorator
hello world
wrapper of decorator
hello world

保留原函數(shù)的元信息

通過greet.name可以輸出函數(shù)的元信息玩敏,你會(huì)發(fā)現(xiàn)斗忌,greet() 函數(shù)被裝飾以后,它的元信息變了聊品。元信息告訴我們“它不再是以前的那個(gè) greet() 函數(shù)飞蹂,而是被 wrapper() 函數(shù)取代了”几苍。為了解決這個(gè)問題翻屈,我們通常使用內(nèi)置的裝飾器@functools.wrap,它會(huì)幫助保留原函數(shù)的元信息(也就是將原函數(shù)的元信息妻坝,拷貝到對應(yīng)的裝飾器函數(shù)里)伸眶。

類裝飾器

前面我們主要講了函數(shù)作為裝飾器的用法,實(shí)際上刽宪,類也可以作為裝飾器厘贼。類裝飾器主要依賴于函數(shù)call(),每當(dāng)你調(diào)用一個(gè)類的示例時(shí)圣拄,函數(shù)call()就會(huì)被執(zhí)行一次嘴秸。

class Count:
    def __init__(self, func):
        self.func = func
        self.num_calls = 0

    def __call__(self, *args, **kwargs):
        self.num_calls += 1
        print('num of calls is: {}'.format(self.num_calls))
        return self.func(*args, **kwargs)

@Count
def example():
    print("hello world")

example()

# 輸出
num of calls is: 1
hello world

example()

# 輸出
num of calls is: 2
hello world

Count裝飾器實(shí)現(xiàn)了記錄調(diào)用次數(shù)的功能。

實(shí)際應(yīng)用

def singleton(cls):
    _instance = {}

    def get_instance():
        if cls not in _instance:
            _instance[cls] = cls()
        return _instance[cls]
    return get_instance

這是裝飾類的裝飾器,用于實(shí)現(xiàn)單例岳掐。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末凭疮,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子串述,更是在濱河造成了極大的恐慌执解,老刑警劉巖,帶你破解...
    沈念sama閱讀 216,651評論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件纲酗,死亡現(xiàn)場離奇詭異衰腌,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)觅赊,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,468評論 3 392
  • 文/潘曉璐 我一進(jìn)店門右蕊,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人吮螺,你說我怎么就攤上這事尤泽。” “怎么了规脸?”我有些...
    開封第一講書人閱讀 162,931評論 0 353
  • 文/不壞的土叔 我叫張陵坯约,是天一觀的道長。 經(jīng)常有香客問我莫鸭,道長闹丐,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,218評論 1 292
  • 正文 為了忘掉前任被因,我火速辦了婚禮卿拴,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘梨与。我一直安慰自己堕花,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,234評論 6 388
  • 文/花漫 我一把揭開白布粥鞋。 她就那樣靜靜地躺著缘挽,像睡著了一般。 火紅的嫁衣襯著肌膚如雪呻粹。 梳的紋絲不亂的頭發(fā)上壕曼,一...
    開封第一講書人閱讀 51,198評論 1 299
  • 那天,我揣著相機(jī)與錄音等浊,去河邊找鬼腮郊。 笑死,一個(gè)胖子當(dāng)著我的面吹牛筹燕,可吹牛的內(nèi)容都是我干的轧飞。 我是一名探鬼主播衅鹿,決...
    沈念sama閱讀 40,084評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼过咬!你這毒婦竟也來了塘安?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 38,926評論 0 274
  • 序言:老撾萬榮一對情侶失蹤援奢,失蹤者是張志新(化名)和其女友劉穎兼犯,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體集漾,經(jīng)...
    沈念sama閱讀 45,341評論 1 311
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡切黔,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,563評論 2 333
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了具篇。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片纬霞。...
    茶點(diǎn)故事閱讀 39,731評論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖驱显,靈堂內(nèi)的尸體忽然破棺而出诗芜,到底是詐尸還是另有隱情,我是刑警寧澤埃疫,帶...
    沈念sama閱讀 35,430評論 5 343
  • 正文 年R本政府宣布伏恐,位于F島的核電站,受9級(jí)特大地震影響栓霜,放射性物質(zhì)發(fā)生泄漏翠桦。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,036評論 3 326
  • 文/蒙蒙 一胳蛮、第九天 我趴在偏房一處隱蔽的房頂上張望销凑。 院中可真熱鬧,春花似錦仅炊、人聲如沸斗幼。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,676評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽蜕窿。三九已至,卻和暖如春督勺,著一層夾襖步出監(jiān)牢的瞬間渠羞,已是汗流浹背斤贰。 一陣腳步聲響...
    開封第一講書人閱讀 32,829評論 1 269
  • 我被黑心中介騙來泰國打工智哀, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人荧恍。 一個(gè)月前我還...
    沈念sama閱讀 47,743評論 2 368
  • 正文 我出身青樓瓷叫,卻偏偏與公主長得像屯吊,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個(gè)殘疾皇子摹菠,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,629評論 2 354

推薦閱讀更多精彩內(nèi)容

  • 函數(shù)對象 在 Python 中盒卸,函數(shù)是一級(jí)對象,它可以賦值給變量次氨,也可以作為參數(shù)傳遞給另外一個(gè)函數(shù)蔽介。 函數(shù)賦值給變...
    佳琪耶閱讀 173評論 0 1
  • 寫在前面 有疑問可在評論處留言,歡迎大家一起交流探討煮寡『缧睿考慮到網(wǎng)頁我可能不經(jīng)常看幸撕,若問題較為緊急薇组,可關(guān)注微信公眾號(hào)「...
    H_biubiu閱讀 828評論 0 2
  • 在python編程中,我們經(jīng)匙看到下面的函數(shù)用法: with open("test.txt", "w") as f...
    hugoren閱讀 821評論 0 0
  • 每個(gè)人都有的內(nèi)褲主要功能是用來遮羞律胀,但是到了冬天它沒法為我們防風(fēng)御寒,咋辦貌矿?我們想到的一個(gè)辦法就是把內(nèi)褲改造一下炭菌,...
    chen_000閱讀 1,362評論 0 3
  • 裝飾器本質(zhì)上是一個(gè)函數(shù),該函數(shù)用來處理其他函數(shù)逛漫,它可以讓其他函數(shù)在不需要修改代碼的前提下增加額外的功能娃兽,裝飾器的返...
    蕭十一郎456閱讀 340評論 0 0