閉包由兩部分組成,一個是返回的函數(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)用場景。