python中閉包與裝飾器

前幾天學(xué)習(xí)python裝飾器時唁桩,看各種例子,上來就是一個嵌套函數(shù)报辱,還返回一個函數(shù)對象(返回內(nèi)嵌函數(shù))单山,學(xué)得我是一臉懵逼啊,覺得太難懂了米奸。今天又來學(xué)習(xí),才發(fā)現(xiàn)慢睡,原來要理解裝飾器铡溪,先得了解閉包的知識。沒錯髓涯,就是閉包哈扮。
閉包又是個什么東西膀驹佟包各?怎么好像更難懂啊。別著急髓棋。。膳犹。其實我之前沒搞懂的那個嵌套函數(shù)就是閉包的寫法,下面記錄了學(xué)習(xí)筆記须床,來一起學(xué)習(xí)吧渐裂。

閉包(closure)

認(rèn)識閉包

咱們用好理解一點的Python的語言介紹一下,一個閉包就是你調(diào)用了一個函數(shù)A族阅,這個函數(shù)A返回了一個函數(shù)B給你膝捞。這個返回的函數(shù)B就叫做閉包。你在調(diào)用函數(shù)A的時候傳遞的參數(shù)就是自由變量
舉個栗子:

def func(name):
    def inner_func(age):
        print 'name:', name, 'age:', age
    return inner_func

bb = func('lucy')
bb(26)  
# >>> name: lucy age: 26

這里面調(diào)用func的時候就產(chǎn)生了一個閉包——inner_func,并且該閉包持有自由變量——name鲤遥,因此這也意味著林艘,當(dāng)函數(shù)func的生命周期結(jié)束之后,name這個變量依然存在钢坦,因為它被閉包引用了咕村,所以不會被回收。

閉包的作用

閉包的最大特點是可以將父函數(shù)的變量與內(nèi)部函數(shù)綁定懈涛,并返回綁定變量后的函數(shù)(也即閉包)批钠,此時即便生成閉包的環(huán)境(父函數(shù))已經(jīng)釋放,閉包仍然存在埋心,這個過程很像類(父函數(shù))生成實例(閉包),不同的是父函數(shù)只在調(diào)用時執(zhí)行闲坎,執(zhí)行完畢后其環(huán)境就會釋放茬斧,而類則在文件執(zhí)行時創(chuàng)建,一般程序執(zhí)行完畢后作用域才釋放项秉,因此對一些需要重用的功能且不足以定義為類的行為,使用閉包會比使用類占用更少的資源怖喻,且更輕巧靈活岁诉。

練習(xí)

如下代碼,求和涕癣,求平均數(shù):

#!/usr/bin/python
# -*-coding:utf-8-*-

def my_sum(*arg):
    a = sum(arg)
    print a
    return a
def my_average(*arg):
    b = sum(arg)/len(arg)
    print b
    return b

my_sum(1,2,3,4,5)
my_average(1,2,3,4,5)

當(dāng)調(diào)用my_sum時傳入的參數(shù)有str,調(diào)用my_average時傳入的參數(shù)為空時代碼會報錯恬叹,所有增加代碼判斷傳入的參數(shù)

#!/usr/bin/python
# -*-coding:utf-8-*-

def my_sum(*arg):
    if len(arg) == 0:
        return 0
    for val in arg:
        if not isinstance(val, int):
            return 0
    a = sum(arg)
    print a
    return a
def my_average(*arg):
    if len(arg) == 0:
        return 0
    for val in arg:
        if not isinstance(val, int):
            return 0
    b = sum(arg)/len(arg)
    print b
    return b

my_sum(1,2,3,4,5)
my_average(1,2,3,4,5)
my_sum(1,2,3,4,5,'6')   # 這2個調(diào)用都會報錯同眯,所有要加判斷,來判斷輸入的參數(shù)
my_average()

那么問題來了须蜗,以上2個函數(shù),每個函數(shù)中對于傳入?yún)?shù)的判斷代碼是重復(fù)的菱农,一旦修改柿估,就需要多個地方修改,工作量就大了的妖,對于代碼的維護也不便。那么怎么優(yōu)化代碼了嫂粟,這時候就可以引入閉包了

#!/usr/bin/python
# -*-coding:utf-8-*-

def my_sum(*arg):
    a = sum(arg)
    print a
    return a
def my_average(*arg):
    b = sum(arg)/len(arg)
    print b
    return b

def dec(func):
    def in_dec(*arg):
        if len(arg) == 0:
            return 0
        for val in arg:
            if not isinstance(val, int):
                return 0
        func(*arg)
    return in_dec

my_sum = dec(my_sum)
my_average =dec(my_average)

my_sum(1,2,3,4,5)
my_average(1,2,3,4,5)
my_sum(1,2,3,4,5,'6')   # 這2個調(diào)用都會報錯,所有要加判斷零抬,來判斷輸入的參數(shù)
my_average()

裝飾器(Decorator)

認(rèn)識裝飾器

“裝飾器的功能是將被裝飾的函數(shù)當(dāng)作參數(shù)傳遞給與裝飾器對應(yīng)的函數(shù)(名稱相同的函數(shù))宽涌,并返回包裝后的被裝飾的函數(shù)”

其實裝飾器就是對閉包的使用

特點:

1、裝飾器是用例裝飾函數(shù)褥芒;
2嫡良、返回一個函數(shù)對象;
3寝受、被標(biāo)識函數(shù)標(biāo)識符指向:返回的函數(shù)對象;
4京闰、語法糖 @

練習(xí)

上面閉包的例子甩苛,使用裝飾器后的代碼如下:

#!/usr/bin/python
# -*-coding:utf-8-*-

def dec(func):
    def in_dec(*arg):
        if len(arg) == 0:
            return 0
        for val in arg:
            if not isinstance(val, int):
                return 0
        func(*arg)
    return in_dec

@dec
def my_sum(*arg):
    a = sum(arg)
    print a
    return a
@dec
def my_average(*arg):
    b = sum(arg)/len(arg)
    print b
    return b

# my_sum = dec(my_sum)
# my_average =dec(my_average)

my_sum(1,2,3,4,5)
my_average(1,2,3,4,5)
my_sum(1,2,3,4,5,'6')   # 這2個調(diào)用都會報錯讯蒲,所有要加判斷,來判斷輸入的參數(shù)
my_average()

實際就是將調(diào)用dec函數(shù)墨林,使用@dec代替

# my_sum = dec(my_sum)
# my_average =dec(my_average)

調(diào)用過程分析:
1旭等、@dec后,my_sum作為一個參數(shù)傳給dec隙袁,dec(my_sum) 返回一個函數(shù)對象in_dec
2、返回的函數(shù)對象in_dec猜揪,由誰來接收呢惭墓?my_sum 原來指向的是求和函數(shù),但現(xiàn)在my_sum 作為一個參數(shù)傳給了dec函數(shù)划咐,然后他當(dāng)作一個enclosing作用域的變量(需要了解函數(shù)作用域LEGB)钧萍,被in_dec函數(shù)所使用,so风瘦,my_sum 重新賦了值万搔,my_sum = in_dec
3、my_average()實際是調(diào)用in_dec(),且裝飾器里重新調(diào)用了my_average()函數(shù)

參考資料:
https://segmentfault.com/a/1190000004461404

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末瞬雹,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子呢诬,更是在濱河造成了極大的恐慌尚镰,老刑警劉巖哪廓,帶你破解...
    沈念sama閱讀 211,265評論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件撩独,死亡現(xiàn)場離奇詭異,居然都是意外死亡综膀,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,078評論 2 385
  • 文/潘曉璐 我一進店門橄登,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人谣妻,你說我怎么就攤上這事√0耄” “怎么了充坑?”我有些...
    開封第一講書人閱讀 156,852評論 0 347
  • 文/不壞的土叔 我叫張陵捻爷,是天一觀的道長。 經(jīng)常有香客問我巡莹,道長甜紫,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,408評論 1 283
  • 正文 為了忘掉前任钉鸯,我火速辦了婚禮唠雕,結(jié)果婚禮上吨述,老公的妹妹穿的比我還像新娘。我一直安慰自己捕儒,他們只是感情好邓夕,可當(dāng)我...
    茶點故事閱讀 65,445評論 5 384
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著焚刚,像睡著了一般点弯。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上矿咕,一...
    開封第一講書人閱讀 49,772評論 1 290
  • 那天抢肛,我揣著相機與錄音狼钮,去河邊找鬼。 笑死捡絮,一個胖子當(dāng)著我的面吹牛熬芜,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播福稳,決...
    沈念sama閱讀 38,921評論 3 406
  • 文/蒼蘭香墨 我猛地睜開眼涎拉,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了灵寺?” 一聲冷哼從身側(cè)響起曼库,我...
    開封第一講書人閱讀 37,688評論 0 266
  • 序言:老撾萬榮一對情侶失蹤略板,失蹤者是張志新(化名)和其女友劉穎叮称,沒想到半個月后瓤檐,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體挠蛉,經(jīng)...
    沈念sama閱讀 44,130評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡谴古,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,467評論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了带饱。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片勺疼。...
    茶點故事閱讀 38,617評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖耕肩,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情婚被,我是刑警寧澤址芯,帶...
    沈念sama閱讀 34,276評論 4 329
  • 正文 年R本政府宣布,位于F島的核電站禀挫,受9級特大地震影響描孟,放射性物質(zhì)發(fā)生泄漏匿醒。R本人自食惡果不足惜缠导,卻給世界環(huán)境...
    茶點故事閱讀 39,882評論 3 312
  • 文/蒙蒙 一憋他、第九天 我趴在偏房一處隱蔽的房頂上張望举瑰。 院中可真熱鬧蔬螟,春花似錦旧巾、人聲如沸鲁猩。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,740評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽闹司。三九已至游桩,卻和暖如春借卧,著一層夾襖步出監(jiān)牢的瞬間铐刘,已是汗流浹背滨达。 一陣腳步聲響...
    開封第一講書人閱讀 31,967評論 1 265
  • 我被黑心中介騙來泰國打工锌订, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人啦辐。 一個月前我還...
    沈念sama閱讀 46,315評論 2 360
  • 正文 我出身青樓紧卒,卻偏偏與公主長得像,于是被迫代替她去往敵國和親轴总。 傳聞我的和親對象是個殘疾皇子怀樟,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 43,486評論 2 348

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