閉包

什么是閉包

我們可以將閉包理解為一個函數(shù)引用了它所在詞法作用域的變量之后形成的一種數(shù)據(jù)結(jié)構(gòu).
詞法作用域顶霞,就是定義一個函數(shù)時(shí)因惭,對它可見的作用域,又叫做環(huán)境哥牍,是由多個作用域組成的棧.舉個例子:

def user_required(user):
    def decorator(fn):
        def wrapper(*args, **kwargs):
            if current_user == user:
                return fn(*args, **kwargs)
            else:
                return no_permission_response
        return wrapper
    return decorator

這個函數(shù)是一個裝飾器非迹,對函數(shù)fn進(jìn)行裝飾后环鲤,就只有特定類型的user可以調(diào)用fn,否則返回no_pemission_response.

這里憎兽,wrapper的詞法作用域就是由decorator形成的部分作用域冷离,user_required的部分作用域以及外面的全局作用域組成,總之就是wrapper能訪問的部分唇兑,也可以稱之為wrapper所處的環(huán)境.

當(dāng)一個函數(shù)引用了它所處環(huán)境的變量的時(shí)候酒朵,比如這里wrapper引用了環(huán)境里的fn和user,這個函數(shù)就形成了一個閉包扎附,這個時(shí)候函數(shù)就不再是一個與外界環(huán)境無關(guān)的函數(shù)蔫耽,而是會因?yàn)橥饨绛h(huán)境改變而改變的函數(shù),引用的環(huán)境變量稱為自由變量.

閉包與作用域

注意形成閉包的時(shí)候閉包保存的是當(dāng)前的環(huán)境留夜,而不是自由變量在此刻的值匙铡,因此不管自由變量是值語義還是引用語義,閉包在執(zhí)行的時(shí)候都會從保存的環(huán)境中獲取它們當(dāng)前的值.舉個經(jīng)常被提起的例子:

def gen_fns():
    return [lambda: x for x in xrange(5)]
print [fn() for fn in gen_fns()]

結(jié)果為[4, 4, 4, 4, 4]

出現(xiàn)這種情況的原因就是Python的列表生成式只會產(chǎn)生一個作用域碍粥,產(chǎn)生的5個閉包保存了同樣的環(huán)境鳖眼,所有的x都是同一個x,gen_fns返回時(shí)x的值是迭代結(jié)束時(shí)的值4,閉包被調(diào)用時(shí)去查找環(huán)境中的x嚼摩,自然就得到了4.
要讓結(jié)果為[0, 1, 2, 3, 4]钦讳,我們可以讓閉包形成時(shí)處在不同的環(huán)境中,注意Python只有類定義和函數(shù)定義(包括lambda)能形成作用域枕面,因此我們可以這樣處理:

def gen_fns():
    return [(lambda x: lambda: x)(x) for x in xrange(5)]
print [fn() for fn in gen_fns()]

這里lambda x: lambda: x中外層的lambda形成了一個作用域愿卒,并且該作用域里的x不是自由變量,而是被外層lambda捕獲而成為僅屬于該作用域的變量潮秘,因此這里產(chǎn)生的5個閉包都保存了一樣的環(huán)境琼开,不一樣的x,而每個x的值都為形成閉包時(shí)的值.

注意閉包和值語義引用語義沒有關(guān)系枕荞,事實(shí)上柜候,僅僅是對變量本身進(jìn)行操作(比如賦值和加減法),值語義和引用語義根本沒有差別搞动,只有對變量進(jìn)行間接操作(其實(shí)也只有引用語義才存在間接操作)(比如調(diào)用變量的set_xxx方法)時(shí),才有可能區(qū)別值語義和引用語義.

閉包的作用

通常一個函數(shù)的返回結(jié)果僅與輸入有關(guān)渣刷,也就是說函數(shù)本身是不保存任何狀態(tài)的鹦肿,而閉包則是保存了環(huán)境(詞法作用域)的函數(shù),其輸出不僅與輸入有關(guān)辅柴,也會受環(huán)境的影響狮惜,不同的環(huán)境產(chǎn)生的閉包是不一樣的,相同的環(huán)境不同的狀態(tài)閉包調(diào)用的結(jié)果也不一樣碌识,通過閉包,我們可以獲取和改變閉包保存的環(huán)境虱而,這樣閉包就成為了環(huán)境之間交互的通道.

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末筏餐,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子牡拇,更是在濱河造成了極大的恐慌魁瞪,老刑警劉巖,帶你破解...
    沈念sama閱讀 212,383評論 6 493
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件惠呼,死亡現(xiàn)場離奇詭異导俘,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)剔蹋,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,522評論 3 385
  • 文/潘曉璐 我一進(jìn)店門旅薄,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人泣崩,你說我怎么就攤上這事少梁。” “怎么了矫付?”我有些...
    開封第一講書人閱讀 157,852評論 0 348
  • 文/不壞的土叔 我叫張陵凯沪,是天一觀的道長。 經(jīng)常有香客問我买优,道長妨马,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,621評論 1 284
  • 正文 為了忘掉前任杀赢,我火速辦了婚禮烘跺,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘葵陵。我一直安慰自己液荸,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,741評論 6 386
  • 文/花漫 我一把揭開白布脱篙。 她就那樣靜靜地躺著娇钱,像睡著了一般伤柄。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上文搂,一...
    開封第一講書人閱讀 49,929評論 1 290
  • 那天适刀,我揣著相機(jī)與錄音,去河邊找鬼煤蹭。 笑死笔喉,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的硝皂。 我是一名探鬼主播常挚,決...
    沈念sama閱讀 39,076評論 3 410
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼稽物!你這毒婦竟也來了奄毡?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,803評論 0 268
  • 序言:老撾萬榮一對情侶失蹤贝或,失蹤者是張志新(化名)和其女友劉穎吼过,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體咪奖,經(jīng)...
    沈念sama閱讀 44,265評論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡盗忱,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,582評論 2 327
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了羊赵。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片趟佃。...
    茶點(diǎn)故事閱讀 38,716評論 1 341
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖慷垮,靈堂內(nèi)的尸體忽然破棺而出揖闸,到底是詐尸還是另有隱情,我是刑警寧澤料身,帶...
    沈念sama閱讀 34,395評論 4 333
  • 正文 年R本政府宣布汤纸,位于F島的核電站,受9級特大地震影響芹血,放射性物質(zhì)發(fā)生泄漏贮泞。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 40,039評論 3 316
  • 文/蒙蒙 一幔烛、第九天 我趴在偏房一處隱蔽的房頂上張望啃擦。 院中可真熱鬧,春花似錦饿悬、人聲如沸令蛉。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,798評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽珠叔。三九已至蝎宇,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間祷安,已是汗流浹背姥芥。 一陣腳步聲響...
    開封第一講書人閱讀 32,027評論 1 266
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留汇鞭,地道東北人凉唐。 一個月前我還...
    沈念sama閱讀 46,488評論 2 361
  • 正文 我出身青樓,卻偏偏與公主長得像霍骄,于是被迫代替她去往敵國和親台囱。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,612評論 2 350

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