閉包

閉包由兩部分組成,一個是返回的函數(shù),一個是原函數(shù)的內(nèi)部變量(或參數(shù))

閉包本身是一個晦澀難懂的概念,不過可以先簡單的理解為:閉包就是一個定義在函數(shù)n內(nèi)部的函數(shù),閉包使得變量即使脫離了該函數(shù)的作用域范圍也依然能被訪問到。

>>> def ma_add(n):
...     return lambda x:x+n
... 
>>> add_3 = ma_add(3)
>>> add_3
<function ma_add.<locals>.<lambda> at 0x0210CD20>
>>> add_3(7)
10

這里的 lambda 函數(shù)就是一個閉包。在全局作用域中,add_3(7) 可以正常執(zhí)行,并且返回值為 10,之所以返回 10 是因為在 ma_add 局部作用域中,變量 n 的值在閉包作用使得它在全局作用域也可以被訪問到。
常規(guī)函數(shù)的閉包:

>>> def my_add(n):
...     def wrapper(x):
...         return x+n
...     return wrapper
...
>>> add_5 = my_add(5)
>>> add_5(2)
7

深入理解閉包:
嵌套函數(shù):

def print_msg():
    # print_msg 是外圍函數(shù)
    msg = "zen of python"

    def printer():
        # printer是嵌套函數(shù)
        print(msg)
    printer()
# 輸出 zen of python
print_msg()

對于嵌套函數(shù),他可以訪問到其外層作用域中聲明的非局部(non-local)變量,比如上面的 msg 變量可以被嵌套函數(shù) printer 正常訪問。但在函數(shù)之外如果 print(msg) ,就會報錯。
閉包:
閉包使得變量在函數(shù)外依然可以被訪問。也就是可以訪問外層函數(shù)的變量。

def print_msg():
    # print_msg 是外圍函數(shù)
    msg = "zen of python"
    def printer():
        # printer 是嵌套函數(shù)
        print(msg)
    return printer

another = print_msg()
# 輸出 zen of python
another()

這段代碼和上段代碼輸出一樣。不同的是,內(nèi)部函數(shù)被直接返回了,注意:返回的并不是結(jié)果,而是這個函數(shù)。

一般情況下,函數(shù)中的局部變量僅在函數(shù)的執(zhí)行期間可用。一旦 print_msg() 執(zhí)行過后,msg 變量不可再用。然而,這里 print_msg 執(zhí)行完后,在調(diào)用 another 的時候, msg 變量的值被正常輸出了。
這段話的意思是,abother 現(xiàn)在相當(dāng)于一個獨立的函數(shù),和 print_msg 函數(shù)是并列關(guān)系,但是 another 能夠訪問 print_msg 函數(shù)里面的變量 msg
another == printer

def printer():
        print(msg)
    return printer

這里的 another 就是一個閉包,閉包本質(zhì)上是一個函數(shù),它由兩部分組成,printer 函數(shù)和變量 msg(print_msg 函數(shù)的參數(shù)也可以)。閉包使得這些變量的值始終保存在內(nèi)存中。

閉包。顧名思義,就是一個封閉的包裹,里面包裹著自由變量,就像在類里面定義的屬性值一樣,自由變量的可見范圍隨同包裹,哪里可以訪問到這個包裹,哪里就可以訪問這個自由變量。

為什么要使用閉包

閉包避免了使用全局變量。此外,閉包允許函數(shù)與其所操縱的某些數(shù)據(jù)(環(huán)境)關(guān)聯(lián)起來。這一點與面向?qū)ο缶幊谭浅O嗨?,在面向?qū)ο缶幊讨?,對象允許我們將某些數(shù)據(jù)(對象的屬性)與一個或者多個辦法相關(guān)聯(lián)。

一般來說,當(dāng)對象中只有一個方法時,使用閉包是最好的選擇:

def adder(x):
    def wrapper(y):
        return x + y
    return wrapper

adder5 = adder(5)
# 輸出 15
adder5(10)
# 輸出 11
adder5(6)

這比用類來實現(xiàn)更優(yōu)雅,此外裝飾器也是基于閉包的一種應(yīng)用場景。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 作用域 作用域是程序運行時變量可被訪問的范圍,定義在函數(shù)內(nèi)的變量是局部變量,局部變量的作用范圍只能是函數(shù)內(nèi)部范圍內(nèi)...
    大川無敵閱讀 383評論 0 0
  • 閉包 閉包,這個名詞第一次看的時候非常懵,通過不斷的復(fù)盤,終于有一點通透的感覺,再次總結(jié)一下 舉例 閉包不是 Py...
    時間之友閱讀 1,779評論 0 0
  • 我在博客中曾經(jīng)介紹過兩篇關(guān)于函數(shù)的文章,第一篇是 關(guān)于 Python 函數(shù)是第一類對象,第二篇是關(guān)于 Lambda...
    liuzhijun閱讀 1,599評論 2 27
  • 前言 對于js中的閉包,無論是老司機(jī)還是小白,我想,見得不能再多了,然而有時三言兩語卻很難說得明白,反正在我初學(xué)時...
    itclanCoder閱讀 4,294評論 1 11
  • 續(xù)上篇有指點說我選取圖片的角度還有很大的進(jìn)步空間,狂補了一下,希望能進(jìn)步一點點,請走過路過繼續(xù)點評~ 原本整個畫面...
    請叫我財迷閱讀 587評論 10 4

友情鏈接更多精彩內(nèi)容