透析Python裝飾器--透過現(xiàn)象看本質(zhì)

》眼花繚亂

Python的裝飾器(也稱語法糖)大致分為這幾類:

  • 無參數(shù)裝飾器
  • 有參數(shù)裝飾器
  • 裝飾類的裝飾器
  • 無參數(shù)類裝飾器
  • 有參數(shù)類裝飾器

:()磕洪,這幾個(gè)分類待會(huì)兒一個(gè)一個(gè)解釋,有可能叫法不一定對(duì)。光是分類就這么多了,如果在弄不清楚裝飾器的本質(zhì),不知要死多少腦細(xì)胞淤堵,媽媽啊、顷扩、拐邪、、隘截、

》撥云見日

我們閑聊點(diǎn)別的扎阶,先看這樣一個(gè)問題:假設(shè)我用了一個(gè)別人的函數(shù)f汹胃,我想加入自己的邏輯,比如在f執(zhí)行前后打印日志东臀,你可能這樣實(shí)現(xiàn):

 def outer_one(f):
    print 'outer_1 before'
    f()
    print 'outer_1 after'

好像實(shí)現(xiàn)了功能着饥,但是只是實(shí)現(xiàn)了部分功能,而且我們希望是一個(gè)新函數(shù)惰赋,如何實(shí)現(xiàn)呢宰掉??赁濒?轨奄?
你問我,可我也不知道拒炎,我們分析一下挪拟,既然是新函數(shù),假設(shè)返回一個(gè)函數(shù)击你,貌似問題解決了舞丛,于是我們有了下面的實(shí)現(xiàn):

def outer_one(f):
    def wrapped():
        print 'outer_1 before'
        f()
        print 'outer_1 after'
    return wrapped

這樣,令new_func=wrapped(f),調(diào)用new_func()果漾,貌似就應(yīng)該是這樣吧

》來點(diǎn)困難的

上面的只是開開眼球切,下面來點(diǎn)難的:

# 無參數(shù)

def outer_three(f):

    def wrapped3():
        print 'outer_3 before'
        f()
        print 'outer_3 after'
    return wrapped3

def outer_two(f):

    def wrapped2():
        print 'outer_two before'
        f()
        print 'outer_two after'
    return wrapped2

def outer_one(f):

    def wrapped1():
        print 'outer_1 before'
        f()
        print 'outer_1 after'
    return wrapped1

def f():
    print 'f'



print "++++++++++++++++++++++="
outer_three(outer_two(outer_one(f)))()
print f.__name__
print "++++++++++++++++++++++="

你能猜猜結(jié)果嘛,特別關(guān)注绒障,new_func=outer_three(outer_two(outer_one(f)))吨凑,這個(gè)表達(dá)式返回的是個(gè)函數(shù),new_func.__name__ 是什么户辱?思考一下再回來鸵钝、、庐镐、


哈哈恩商,第二個(gè)答案是outer_three的wrapped3。
這個(gè)問題的關(guān)鍵是弄清outer_three(outer_two(outer_one(f)))這個(gè)表達(dá)式是如何執(zhí)行的必逆,它是從內(nèi)到外執(zhí)行的怠堪,也就是,outer_one返回的wrapped1會(huì)作為outer_two的參數(shù)名眉,即粟矿,f=wrapped1。


再來點(diǎn)復(fù)雜的损拢,如果要傳遞參數(shù)該怎么寫呢陌粹?

# 有參數(shù)

def outer_three(f):

    def wrapped(a):
        print 'outer_3 before'
        f(a)
        print 'outer_3 after'
    return wrapped

def outer_two(f):

    def wrapped(a):
        print 'outer_two before'
        f(a)
        print 'outer_two after'
    return wrapped

def outer_one(f):

    def wrapped(a):
        print 'outer_1 before'
        f(a)
        print 'outer_1 after'
    return wrapped

def f(a):
    print 'f:',a

print "++++++++++++++++++++++="
outer_three(outer_two(outer_one(f)))(123132)
print f.__name__
print "++++++++++++++++++++++="

調(diào)用圖如下:


call.jpg

》言歸正傳

我們看個(gè)栗子:
# first,無參數(shù)裝飾器
def wrapper_func(f):
print f.name
def wrapped(a):
f(a)
return wrapped

    @wrapper_func
    def func(a):
        print a
        print locals()


    print "++++++++++++++++++++++="
    func(234)
    print func
    print "++++++++++++++++++++++="

其實(shí)這個(gè)語法糖幫你做了一個(gè)這樣的事情,func = wrapper_func(func)

__這就是裝飾器的本質(zhì) __

師兄只能幫你到這里了福压,剩下的看你了 :------》,

什么還不懂掏秩,再提示幾點(diǎn)或舞,

  • 有參數(shù)時(shí),func = wrapper_func(args1)(func)(args2)蒙幻,args1傳給了wrapper_func()映凳,而args2 傳給了func
  • 對(duì)于class,如果想這樣用杆煞,MyClass(args)(args),需要重寫MyClass的__call__方法
  • 考慮下魏宽,func在什么時(shí)候被調(diào)包了
  • 考慮下腐泻,現(xiàn)在的func的名字已經(jīng)不是func了决乎,如何讓它的名字恢復(fù)
  • 如果有返回值該怎么辦?return

好了派桩,代碼如下:

  # first,無參數(shù)裝飾器
    def wrapper_func(f):
        print f.__name__
        def wrapped(a):
            f(a)
        return wrapped

    @wrapper_func
    def func(a):
        print a
        print locals()


    print "++++++++++++++++++++++="
    func(234)
    print func
    print "++++++++++++++++++++++="


    # second构诚,有參數(shù)裝飾器

    def wrapper_one(arg):
        print 's:',arg
        def wrapper_two(f):
            def wrapper_three(a):
                print 'a', a
                f(a)
            return wrapper_three 
        return wrapper_two


    @wrapper_one('sfdsf')
    def func2(s):
        print s


    print "++++++++++++++++++++++="
    func2(34)
    print func2
    print "++++++++++++++++++++++="


    # three, 裝飾類的裝飾器

    def wrapper_cls(cls):
        def wrapperd_cls(*args,**kwgs):
            cls(*args,**kwgs)

        return wrapperd_cls

    @wrapper_cls
    class MyClass(object):
        pass

    print "++++++++++++++++++++++="
    print MyClass()
    print MyClass
    print "++++++++++++++++++++++="

    # four铆惑, 裝飾器是一個(gè)類, 無參數(shù)
    class wrapper_class(object):
        def __init__(self,func):
            self.func=func

        def __call__(self,*args,**kwgs):
            self.func(*args,**kwgs)

    @wrapper_class
    def func3(a):
        print a


    print "++++++++++++++++++++++="
    print func3(5)
    print func3
    print "++++++++++++++++++++++="



    # four范嘱, 裝飾器是一個(gè)類,有參數(shù)
    class wrapper_class2(object):
        def __init__(self,args):
           print 'cls',args

        def __call__(self,func):
            def wrapper_inner(*args,**kwgs):
                func(*args,**kwgs)
            return wrapper_inner


    @wrapper_class2(123)
    def func4(a):
        print a


    print "++++++++++++++++++++++="
    print func4(5)
    print func4
    print "++++++++++++++++++++++="
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市员魏,隨后出現(xiàn)的幾起案子丑蛤,更是在濱河造成了極大的恐慌,老刑警劉巖撕阎,帶你破解...
    沈念sama閱讀 221,198評(píng)論 6 514
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件受裹,死亡現(xiàn)場離奇詭異,居然都是意外死亡虏束,警方通過查閱死者的電腦和手機(jī)棉饶,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,334評(píng)論 3 398
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來镇匀,“玉大人照藻,你說我怎么就攤上這事『骨郑” “怎么了幸缕?”我有些...
    開封第一講書人閱讀 167,643評(píng)論 0 360
  • 文/不壞的土叔 我叫張陵,是天一觀的道長晰韵。 經(jīng)常有香客問我冀值,道長,這世上最難降的妖魔是什么宫屠? 我笑而不...
    開封第一講書人閱讀 59,495評(píng)論 1 296
  • 正文 為了忘掉前任列疗,我火速辦了婚禮,結(jié)果婚禮上浪蹂,老公的妹妹穿的比我還像新娘抵栈。我一直安慰自己告材,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,502評(píng)論 6 397
  • 文/花漫 我一把揭開白布古劲。 她就那樣靜靜地躺著斥赋,像睡著了一般。 火紅的嫁衣襯著肌膚如雪产艾。 梳的紋絲不亂的頭發(fā)上疤剑,一...
    開封第一講書人閱讀 52,156評(píng)論 1 308
  • 那天,我揣著相機(jī)與錄音闷堡,去河邊找鬼隘膘。 笑死,一個(gè)胖子當(dāng)著我的面吹牛杠览,可吹牛的內(nèi)容都是我干的弯菊。 我是一名探鬼主播,決...
    沈念sama閱讀 40,743評(píng)論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼踱阿,長吁一口氣:“原來是場噩夢(mèng)啊……” “哼管钳!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起软舌,我...
    開封第一講書人閱讀 39,659評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤才漆,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后佛点,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體醇滥,經(jīng)...
    沈念sama閱讀 46,200評(píng)論 1 319
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,282評(píng)論 3 340
  • 正文 我和宋清朗相戀三年恋脚,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片糟描。...
    茶點(diǎn)故事閱讀 40,424評(píng)論 1 352
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡怀喉,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出船响,到底是詐尸還是另有隱情躬拢,我是刑警寧澤,帶...
    沈念sama閱讀 36,107評(píng)論 5 349
  • 正文 年R本政府宣布见间,位于F島的核電站聊闯,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏米诉。R本人自食惡果不足惜菱蔬,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,789評(píng)論 3 333
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧拴泌,春花似錦魏身、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,264評(píng)論 0 23
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至回季,卻和暖如春家制,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背泡一。 一陣腳步聲響...
    開封第一講書人閱讀 33,390評(píng)論 1 271
  • 我被黑心中介騙來泰國打工颤殴, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人瘾杭。 一個(gè)月前我還...
    沈念sama閱讀 48,798評(píng)論 3 376
  • 正文 我出身青樓诅病,卻偏偏與公主長得像哪亿,于是被迫代替她去往敵國和親粥烁。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,435評(píng)論 2 359

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

  • 呵呵蝇棉!作為一名教python的老師讨阻,我發(fā)現(xiàn)學(xué)生們基本上一開始很難搞定python的裝飾器,也許因?yàn)檠b飾器確實(shí)很難懂...
    TypingQuietly閱讀 19,556評(píng)論 26 186
  • Python的裝飾器的英文名叫Decorator篡殷,要對(duì)一個(gè)已有的模塊做一些“修飾工作”钝吮,所謂修飾工作就是想給現(xiàn)有的...
    Spareribs閱讀 676評(píng)論 1 11
  • *** 版權(quán)聲明: 以下文章都是從互聯(lián)網(wǎng)上收集并整理而成的。 *** iOS iOS開發(fā)路線簡述 iOS開發(fā)60分...
    dibadalu閱讀 1,961評(píng)論 2 44
  • 八月初偶然拍的一張照片板辽,今天翻開相冊(cè)突然覺得好美奇瘦。 于是簡單的調(diào)了一下色,鄉(xiāng)下的小白房和落日的余暉相互映襯劲弦,好美好...
    不得意也須盡歡閱讀 190評(píng)論 0 1
  • 淡淡的慵懶的旋律,溫柔這個(gè)微涼的夜晚画畅。 時(shí)間是什么樣子砸琅?有很棒的夢(mèng)想,有過熬夜奮斗很累但很有成就感的感覺轴踱,有夜深人...
    李艷菲閱讀 358評(píng)論 2 0