python閉包

返回函數(shù)

函數(shù)作為返回值

高階函數(shù)除了可以接受函數(shù)作為參數(shù)外耗绿,還可以把函數(shù)作為結(jié)果值返回。
我們來(lái)實(shí)現(xiàn)一個(gè)可變參數(shù)的求和。通常情況下鹅心,求和的函數(shù)是這樣定義的:

def calc_sum(*args):
    ax = 0
    for n in args:
        ax = ax + n
    return ax

但是,如果不需要立刻求和纺荧,而是在后面的代碼中旭愧,根據(jù)需要再計(jì)算怎么辦颅筋?可以不返回求和的結(jié)果,而是返回求和的函數(shù)输枯!

def lazy_sum(*args):
    def sum():
        ax = 0
        for n in args:
            ax = ax + n
        return ax
    return sum

當(dāng)我們調(diào)用lazy_sum()時(shí)议泵,返回的并不是求和的結(jié)果,而是求和函數(shù):

>>>f = lazy_sum(1, 2, 3, 4)
>>>f
<function sum at 0x10452f668>

調(diào)用函數(shù)f時(shí)桃熄,才真正計(jì)算求和的結(jié)果:

>>>f()
10

在這個(gè)例子中先口,我們?cè)诤瘮?shù)lazy_sum中又定義了函數(shù)sum,內(nèi)部函數(shù)sum可以引用外部函數(shù)lazy_sum的參數(shù)和局部變量瞳收,當(dāng)lazy_sum返回函數(shù)sum時(shí)碉京,相關(guān)參數(shù)和變量都保存在返回的函數(shù)中,這種稱為閉包(Closure)的程序結(jié)構(gòu)擁有極大的威力螟深。

請(qǐng)?jiān)僮⒁庖幌滦持妫?dāng)我們調(diào)用lazy_sum()時(shí),每次調(diào)用都會(huì)返回一個(gè)新的函數(shù)界弧,即使傳入相同的參數(shù):

>>>f1 = lazy_sum(1, 3, 5, 7, 9)
>>>f2 = lazy_sum(1, 3, 5, 7, 9)
>>>f1 == f2
False

f1()f()的調(diào)用結(jié)果互不影響卧惜。

閉包

注意到返回的函數(shù)在其定義內(nèi)部引用了局部變量args,所以夹纫,當(dāng)一個(gè)函數(shù)返回了一個(gè)函數(shù)后咽瓷,其內(nèi)部的局部變量還被新函數(shù)引用,所以舰讹,閉包用起來(lái)簡(jiǎn)單茅姜,實(shí)現(xiàn)起來(lái)可不容易。

另一個(gè)需要注意的問(wèn)題月匣,返回的函數(shù)并沒(méi)有立刻執(zhí)行钻洒,而是知道調(diào)用了f()才執(zhí)行。我們來(lái)看一個(gè)例子:

def count()
    fs = []
    for i in range(1, 4):
        def f():
            return i * i
        fs.append(f)
    return fs

f1, f2, f3 = count()

在上面的例子中锄开,每次循環(huán)素标,都創(chuàng)建了一個(gè)新的函數(shù),然后萍悴,把創(chuàng)建的3個(gè)函數(shù)都返回了头遭。

你可能認(rèn)為調(diào)用f1(), f2(), f3()結(jié)果應(yīng)該是1, 4, 9,但實(shí)際結(jié)果是:

>>>f1()
9
>>>f2()
9
>>>f3()
9

全部都是9!原因就在于返回的函數(shù)引用了變量i,但它并非立刻執(zhí)行癣诱。等到3個(gè)函數(shù)都返回時(shí)计维,他們引用的變量i已經(jīng)變成了3, 因此撕予,最終結(jié)果為9

返回閉包時(shí)要牢記的一點(diǎn)就是:返回函數(shù)不要引用任何循環(huán)變量鲫惶,或者后續(xù)會(huì)發(fā)生變化的變量。

如果一定要引用循環(huán)變量怎么辦实抡?方法就是再創(chuàng)建一個(gè)函數(shù)欠母,用該函數(shù)的參數(shù)綁定循環(huán)變量當(dāng)前的值欢策,無(wú)論循環(huán)變量后續(xù)如何更改,已綁定到函數(shù)參數(shù)的值不變:

def count():
    fs = []
    for i in range(1, 4):
        def f(j):
            def g():
                return j*j
            return g
        fs.append(f(j))
    return fs

>>>f1, f2, f3 = count()
>>>f1()
1
>>>f2()
4

缺點(diǎn)是代碼較長(zhǎng)赏淌,可利用lambda函數(shù)縮短代碼猬腰。

def count():
    fs = []
    for i in range(1, 4):
        def f(j):
            return lambda:j*j
        fs.append(f(i))
    return fs
f1, f2, f3 = count()
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市猜敢,隨后出現(xiàn)的幾起案子姑荷,更是在濱河造成了極大的恐慌,老刑警劉巖缩擂,帶你破解...
    沈念sama閱讀 217,657評(píng)論 6 505
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件鼠冕,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡胯盯,警方通過(guò)查閱死者的電腦和手機(jī)懈费,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,889評(píng)論 3 394
  • 文/潘曉璐 我一進(jìn)店門(mén),熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)博脑,“玉大人憎乙,你說(shuō)我怎么就攤上這事〔嫒ぃ” “怎么了泞边?”我有些...
    開(kāi)封第一講書(shū)人閱讀 164,057評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)疗杉。 經(jīng)常有香客問(wèn)我阵谚,道長(zhǎng),這世上最難降的妖魔是什么烟具? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,509評(píng)論 1 293
  • 正文 為了忘掉前任梢什,我火速辦了婚禮,結(jié)果婚禮上朝聋,老公的妹妹穿的比我還像新娘嗡午。我一直安慰自己,他們只是感情好冀痕,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,562評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布荔睹。 她就那樣靜靜地躺著,像睡著了一般金度。 火紅的嫁衣襯著肌膚如雪应媚。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 51,443評(píng)論 1 302
  • 那天猜极,我揣著相機(jī)與錄音,去河邊找鬼消玄。 笑死跟伏,一個(gè)胖子當(dāng)著我的面吹牛丢胚,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播受扳,決...
    沈念sama閱讀 40,251評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼携龟,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了勘高?” 一聲冷哼從身側(cè)響起峡蟋,我...
    開(kāi)封第一講書(shū)人閱讀 39,129評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎华望,沒(méi)想到半個(gè)月后蕊蝗,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,561評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡赖舟,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,779評(píng)論 3 335
  • 正文 我和宋清朗相戀三年蓬戚,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片宾抓。...
    茶點(diǎn)故事閱讀 39,902評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡子漩,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出石洗,到底是詐尸還是另有隱情幢泼,我是刑警寧澤,帶...
    沈念sama閱讀 35,621評(píng)論 5 345
  • 正文 年R本政府宣布讲衫,位于F島的核電站旭绒,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏焦人。R本人自食惡果不足惜挥吵,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,220評(píng)論 3 328
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望花椭。 院中可真熱鬧忽匈,春花似錦、人聲如沸矿辽。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,838評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)袋倔。三九已至雕蔽,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間宾娜,已是汗流浹背批狐。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 32,971評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人嚣艇。 一個(gè)月前我還...
    沈念sama閱讀 48,025評(píng)論 2 370
  • 正文 我出身青樓承冰,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親食零。 傳聞我的和親對(duì)象是個(gè)殘疾皇子困乒,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,843評(píng)論 2 354

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

  • 一、python函數(shù)作用域LEGB python解釋器查找變量的原則(順序):L→E→G→BL:Local函數(shù)內(nèi)部...
    風(fēng)蕭雨霖閱讀 452評(píng)論 0 0
  • 閉包(closure)是函數(shù)式編程的重要的語(yǔ)法結(jié)構(gòu)贰谣。函數(shù)式編程是一種編程范式 (而面向過(guò)程編程和面向?qū)ο缶幊桃捕际?..
    Mr_Chen閱讀 316評(píng)論 0 1
  • 函數(shù)作為返回值 高階函數(shù)除了可以接受函數(shù)作為參數(shù)外娜搂,還可以把函數(shù)作為結(jié)果值返回。 我們來(lái)實(shí)現(xiàn)一個(gè)可變參數(shù)的求和吱抚。通...
    喵在野閱讀 286評(píng)論 0 1
  • 莫言最美的一首詩(shī): 你若懂我 該有多好 每個(gè)人都有一個(gè)死角百宇, 自己走不出來(lái), 別人也闖不進(jìn)去频伤。 我把最深沉的秘密放...
    粉色的桃林閱讀 436評(píng)論 13 14
  • 耳邊跳動(dòng)的小精靈 很多人以為穿金戴銀就是好看恳谎,但是一個(gè)小小的點(diǎn)綴就美翻天啦。 秋冬黑乎乎的衣服中增加點(diǎn)色彩憋肖,性感的...
    IN女王閱讀 313評(píng)論 0 1