說說 Python 中的閉包

閉包不好理解,所以先從示例說起与学。

假設我們需要計算平均值谱煤,這些值會從外層傳遞進來摊求,然后被保存在內(nèi)部。

(1) 非閉包方式實現(xiàn)

class Averager():

    def __init__(self):
        self.series = []

    def __call__(self, new_value):
        self.series.append(new_value)
        total = sum(self.series)
        return total / len(self.series)


avg = Averager()
logging.info('avg(10) -> %s', avg(10))
logging.info('avg(20) -> %s', avg(20))
logging.info('avg(30) -> %s', avg(30))

運行結果:


  1. 非閉包方式定義了一個類刘离,名為 Averager室叉。然后在初始化方法中為該類定義了一個數(shù)組 series,用于保存?zhèn)魅脒M來的數(shù)值硫惕。
  2. 接著使用 __call__ 使得該類實例對象可以像調(diào)用普通函數(shù)那樣茧痕,以“對象名()”的形式被使用1。它接收一個參數(shù)作為需要計算的新數(shù)值恼除,內(nèi)部被保存在 series 數(shù)組中踪旷。

(2) 閉包方式實現(xiàn)

這個平均數(shù)計算方式可以采用函數(shù)式編程方式來實現(xiàn)。

def make_averager():
    series = []

    def averager(new_value):
        series.append(new_value)
        total = sum(series)
        return total / len(series)

    return averager


avg = make_averager()
logging.info('avg(10) -> %s', avg(10))
logging.info('avg(20) -> %s', avg(20))
logging.info('avg(30) -> %s', avg(30))

運行結果與上例相同。

  1. 我們定義了一個 make_averager 函數(shù)令野,其內(nèi)部又定義了一個名為 averager(new_value) 的函數(shù)舀患,里面是計算平均數(shù)的算法;
  2. 傳入的參數(shù)被保存在外層的 series 數(shù)組中气破;
  3. 最后返回這個內(nèi)部函數(shù)聊浅。

黃色區(qū)域表示產(chǎn)生閉包現(xiàn)象的代碼段。其中的 series 數(shù)組是自由變量(free variable)堵幽,不受內(nèi)部函數(shù) averager 的影響狗超,所以可以保存所有傳入的變量值。

內(nèi)部函數(shù) averager 的局部作用域內(nèi)的變量朴下,都會在函數(shù)被調(diào)用后失效努咐。

通過 __code__ 屬性可以看到 avg 函數(shù)中的變量名稱。__code__ 屬性是編譯后的函數(shù)定義體殴胧。

logging.info('avg.__code__.co_varnames -> %s', avg.__code__.co_varnames)
logging.info('avg.__code__.co_freevars -> %s', avg.__code__.co_freevars)

運行結果:


其中 co_varnames 表示局部變量渗稍;co_freevars 表示自由變量。這與我們之前所描述的閉包場景一致团滥。

閉包中的自由變量值保存在 avg 函數(shù)的 __closure__ 屬性中竿屹。它是一組 cell 對象列表,每個 cell 對象與 co_freevars 列表中的名稱一一對應:

INFO - avg.__closure__ -> (<cell at 0x000002A8AF736D38: list object at 0x000002A8AF9C7DC8>,)
INFO - avg.__closure__[0].cell_contents -> [10, 20, 30]

運行結果:


closure 翻譯過來就是閉包灸姊。


通過閉包拱燃,我們可以保留住定義的自由變量的值。這樣函數(shù)調(diào)用后力惯,我們?nèi)匀豢梢允褂眠@些變量碗誉。


  1. Python __call__()方法(詳解版).
  2. Luciano Ramalho (作者),安道父晶,吳珂 (譯者).流暢的Python[M].人民郵電出版社哮缺,2017:312-315.
?著作權歸作者所有,轉載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市甲喝,隨后出現(xiàn)的幾起案子尝苇,更是在濱河造成了極大的恐慌,老刑警劉巖埠胖,帶你破解...
    沈念sama閱讀 212,454評論 6 493
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件糠溜,死亡現(xiàn)場離奇詭異,居然都是意外死亡押袍,警方通過查閱死者的電腦和手機诵冒,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,553評論 3 385
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來谊惭,“玉大人汽馋,你說我怎么就攤上這事侮东。” “怎么了豹芯?”我有些...
    開封第一講書人閱讀 157,921評論 0 348
  • 文/不壞的土叔 我叫張陵悄雅,是天一觀的道長。 經(jīng)常有香客問我铁蹈,道長宽闲,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,648評論 1 284
  • 正文 為了忘掉前任握牧,我火速辦了婚禮容诬,結果婚禮上,老公的妹妹穿的比我還像新娘沿腰。我一直安慰自己览徒,他們只是感情好,可當我...
    茶點故事閱讀 65,770評論 6 386
  • 文/花漫 我一把揭開白布颂龙。 她就那樣靜靜地躺著习蓬,像睡著了一般。 火紅的嫁衣襯著肌膚如雪措嵌。 梳的紋絲不亂的頭發(fā)上躲叼,一...
    開封第一講書人閱讀 49,950評論 1 291
  • 那天,我揣著相機與錄音企巢,去河邊找鬼枫慷。 笑死,一個胖子當著我的面吹牛浪规,可吹牛的內(nèi)容都是我干的流礁。 我是一名探鬼主播,決...
    沈念sama閱讀 39,090評論 3 410
  • 文/蒼蘭香墨 我猛地睜開眼罗丰,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了再姑?” 一聲冷哼從身側響起萌抵,我...
    開封第一講書人閱讀 37,817評論 0 268
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎元镀,沒想到半個月后绍填,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,275評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡栖疑,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,592評論 2 327
  • 正文 我和宋清朗相戀三年讨永,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片遇革。...
    茶點故事閱讀 38,724評論 1 341
  • 序言:一個原本活蹦亂跳的男人離奇死亡卿闹,死狀恐怖揭糕,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情锻霎,我是刑警寧澤著角,帶...
    沈念sama閱讀 34,409評論 4 333
  • 正文 年R本政府宣布,位于F島的核電站旋恼,受9級特大地震影響吏口,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜冰更,卻給世界環(huán)境...
    茶點故事閱讀 40,052評論 3 316
  • 文/蒙蒙 一产徊、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧蜀细,春花似錦舟铜、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,815評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至涣觉,卻和暖如春痴荐,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背官册。 一陣腳步聲響...
    開封第一講書人閱讀 32,043評論 1 266
  • 我被黑心中介騙來泰國打工生兆, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人膝宁。 一個月前我還...
    沈念sama閱讀 46,503評論 2 361
  • 正文 我出身青樓鸦难,卻偏偏與公主長得像,于是被迫代替她去往敵國和親员淫。 傳聞我的和親對象是個殘疾皇子合蔽,可洞房花燭夜當晚...
    茶點故事閱讀 43,627評論 2 350

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

  • 原文出處: cicaday Python中的閉包不是一個一說就能明白的概念,但是隨著你往學習的深入介返,無論如何你都需...
    PyChina閱讀 403評論 0 1
  • 本文的文字及圖片來源于網(wǎng)絡,僅供學習拴事、交流使用,不具有任何商業(yè)用途,如有問題請及時聯(lián)系我們以作處理 最近閱讀《流暢...
    葡萄_ac1c閱讀 193評論 0 0
  • 閉包是指延伸了作用域的函數(shù),其中包含函數(shù)定義體中引用圣蝎、但是不在定義體中定義的非全局變量刃宵。閉包(closure)是函...
    ByiProX閱讀 238評論 0 0
  • 閉包和裝飾器 1.8 閉包和裝飾器 學習目標 1. 能夠說出閉包的定義形式 2. 能夠說出裝飾器的實現(xiàn)形式 ...
    Cestine閱讀 534評論 0 0
  • @Author : Roger TX (425144880@qq.com) @Link : https:/...
    Roger田翔閱讀 323評論 0 1