Python 深入理解閉包

2021-09-11 14:53:26 字數 2425 閱讀 5147

函式物件是使用def語句定義的,函式物件的作用域與def所在的層級相同。比如下面**,我們在line_conf函式的隸屬範圍內定義的函式line,就只能在line_conf的隸屬範圍內呼叫。 

**:

def line_conf():

def line(x):

return 2 * x + 1

print(line(5)) #within the scope

line_conf()

print(line(5)) #out of the scope

執行:

11

traceback (most recent call last):

file "c:/users/desktop/1.py", line 6, in print(line(5))

nameerror: name 'line' is not defined

函式是乙個物件,所以可以作為某個函式的返回結果。 

**:

def line_conf():

def line(x):

return 2 * x + 1

return line # return a function object

my_line = line_conf()

print(my_line(5))

執行:

11
如果line()的定義中引用了外部的變數,會發生什麼呢? 

**:

def line_conf():

b = 15

def line(x):

return 2*x+b # line()引用了外部變數b

return line # return a function object

b = 5

my_line = line_conf()

print(my_line(5))

執行:

25
我們可以看到,line定義的隸屬程式塊中引用了高層級的變數b,但b資訊存在於line的定義之外 (b的定義並不在line的隸屬程式塊中)。我們稱b為line的環境變數。事實上,line作為line_conf的返回值時,line中已經包括b的取值(儘管b並不隸屬於line)。

下面的**將列印25,也就是說,line所參照的b值是函式物件定義時可供參考的b值,而不是使用時的b值。

乙個函式和它的環境變數合在一起,就構成了乙個閉包(closure)。在python中,所謂的閉包是乙個包含有環境變數取值的函式物件。環境變數取值被儲存在函式物件的closure屬性中。比如下面的**:

def line_conf():

b = 15

def line(x):

return 2*x+b

return line # return a function object

執行:

>>> 

>>> b = 5

>>> my_line = line_conf()

>>> print(my_line.__closure__)

(,)>>> print(my_line.__closure__[0].cell_contents)

15>>>

closure裡包含了乙個元組(tuple)。這個元組中的每個元素是cell型別的物件。我們看到第乙個cell包含的就是整數15,也就是我們建立閉包時的環境變數b的取值(而不是外面的值b=5)。

下面看乙個閉包的實際例子:

def line_conf(a, b):

def line(x):

return a*x + b

return line

line1 = line_conf(1, 1)

line2 = line_conf(4, 5)

print(line1(5), line2(5))

執行

6.25
這個例子中,函式line與環境變數a,b構成閉包。在建立閉包的時候,我們通過line_conf的引數a,b說明了這兩個環境變數的取值,這樣,我們就確定了函式的最終形式(y = x + 1和y = 4x + 5)。我們只需要變換引數a,b,就可以獲得不同的直線表達函式。由此,我們可以看到,閉包也具有提高**可復用性的作用。

如果沒有閉包,我們需要每次建立直線函式的時候同時說明a,b,x。這樣,我們就需要更多的引數傳遞,也減少了**的可移植性。利用閉包,我們實際上建立了泛函。line函式定義一種廣泛意義的函式。這個函式的一些方面已經確定(必須是直線),但另一些方面(比如a和b引數待定)。隨後,我們根據line_conf傳遞來的引數,通過閉包的形式,將最終函式確定下來。

深入理解閉包

閉包的定義 mdn 對閉包的定義 根據上面的例子,舉乙個例子 var str xiaoqi function getname getname 函式可以返回str這個變數,但str即不是getname函式的區域性變數,也不是foo函式的引數,所以str就是自由變數。這樣函式getname就是乙個閉包。...

深入理解JavaScript閉包

一 什麼是閉包 多個 兩個或兩個以上 函式巢狀,當內部函式被儲存到外部時,將會生成閉包。內部函式在外面執行的時候一定能夠呼叫的了原來它在的那個函式環境裡的變數。閉包會導致原有作用域鏈不釋放,造成記憶體洩露。functiona var aaa 123 return b var glob 100 var...

swift深入理解閉包

我們可用swift的閉包來定義變數的值。先來乙個簡單的例子大家先感受感受。定義乙個字串的變數的方法 直接賦值 var string a string 還可以用閉包的方式定義 var string1 string 閉包還可以這麼定義,省略了等號和括號 var string2 string 閉包中可以定...