国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 編程 > Python > 正文

Python深入學習之閉包

2019-11-25 18:14:43
字體:
來源:轉載
供稿:網(wǎng)友

閉包(closure)是函數(shù)式編程的重要的語法結構。函數(shù)式編程是一種編程范式 (而面向過程編程和面向對象編程也都是編程范式)。在面向過程編程中,我們見到過函數(shù)(function);在面向對象編程中,我們見過對象(object)。函數(shù)和對象的根本目的是以某種邏輯方式組織代碼,并提高代碼的可重復使用性(reusability)。閉包也是一種組織代碼的結構,它同樣提高了代碼的可重復使用性。

不同的語言實現(xiàn)閉包的方式不同。Python以函數(shù)對象為基礎,為閉包這一語法結構提供支持的 (我們在特殊方法與多范式中,已經(jīng)多次看到Python使用對象來實現(xiàn)一些特殊的語法)。Python一切皆對象,函數(shù)這一語法結構也是一個對象。在函數(shù)對象中,我們像使用一個普通對象一樣使用函數(shù)對象,比如更改函數(shù)對象的名字,或者將函數(shù)對象作為參數(shù)進行傳遞。

函數(shù)對象的作用域

和其他對象一樣,函數(shù)對象也有其存活的范圍,也就是函數(shù)對象的作用域。函數(shù)對象是使用def語句定義的,函數(shù)對象的作用域與def所在的層級相同。比如下面代碼,我們在line_conf函數(shù)的隸屬范圍內定義的函數(shù)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


line函數(shù)定義了一條直線(y = 2x + 1)??梢钥吹剑趌ine_conf()中可以調用line函數(shù),而在作用域之外調用line將會有下面的錯誤:
復制代碼 代碼如下:

NameError: name 'line' is not defined

說明這時已經(jīng)在作用域之外。

同樣,如果使用lambda定義函數(shù),那么函數(shù)對象的作用域與lambda所在的層級相同。

閉包

函數(shù)是一個對象,所以可以作為某個函數(shù)的返回結果。

復制代碼 代碼如下:

def line_conf():
    def line(x):
        return 2*x+1
    return line       # return a function object

my_line = line_conf()
print(my_line(5))      

上面的代碼可以成功運行。line_conf的返回結果被賦給line對象。上面的代碼將打印11。

如果line()的定義中引用了外部的變量,會發(fā)生什么呢?

復制代碼 代碼如下:

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(5))      


我們可以看到,line定義的隸屬程序塊中引用了高層級的變量b,但b信息存在于line的定義之外 (b的定義并不在line的隸屬程序塊中)。我們稱b為line的環(huán)境變量。事實上,line作為line_conf的返回值時,line中已經(jīng)包括b的取值(盡管b并不隸屬于line)。

上面的代碼將打印25,也就是說,line所參照的b值是函數(shù)對象定義時可供參考的b值,而不是使用時的b值。

一個函數(shù)和它的環(huán)境變量合在一起,就構成了一個閉包(closure)。在Python中,所謂的閉包是一個包含有環(huán)境變量取值的函數(shù)對象。環(huán)境變量取值被保存在函數(shù)對象的__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)

__closure__里包含了一個元組(tuple)。這個元組中的每個元素是cell類型的對象。我們看到第一個cell包含的就是整數(shù)15,也就是我們創(chuàng)建閉包時的環(huán)境變量b的取值。

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

復制代碼 代碼如下:

def line_conf(a, b):
    def line(x):
        return ax + b
    return line

line1 = line_conf(1, 1)
line2 = line_conf(4, 5)
print(line1(5), line2(5))


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

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

閉包與并行運算

閉包有效的減少了函數(shù)所需定義的參數(shù)數(shù)目。這對于并行運算來說有重要的意義。在并行運算的環(huán)境下,我們可以讓每臺電腦負責一個函數(shù),然后將一臺電腦的輸出和下一臺電腦的輸入串聯(lián)起來。最終,我們像流水線一樣工作,從串聯(lián)的電腦集群一端輸入數(shù)據(jù),從另一端輸出數(shù)據(jù)。這樣的情境最適合只有一個參數(shù)輸入的函數(shù)。閉包就可以實現(xiàn)這一目的。

并行運算正稱為一個熱點。這也是函數(shù)式編程又熱起來的一個重要原因。函數(shù)式編程早在1950年代就已經(jīng)存在,但應用并不廣泛。然而,我們上面描述的流水線式的工作并行集群過程,正適合函數(shù)式編程。由于函數(shù)式編程這一天然優(yōu)勢,越來越多的語言也開始加入對函數(shù)式編程范式的支持。

發(fā)表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發(fā)表
主站蜘蛛池模板: 民丰县| 临海市| 福州市| 宣武区| 白河县| 威信县| 淅川县| 溆浦县| 连山| 大化| 会泽县| 长葛市| 承德县| 盈江县| 广水市| 姚安县| 西华县| 曲靖市| 厦门市| 临沧市| 新乐市| 静宁县| 夏津县| 石景山区| 景谷| 临安市| 旺苍县| 阜新| 余干县| 深圳市| 师宗县| 汶上县| 沭阳县| 马公市| 济源市| 阿拉尔市| 通州市| 诸城市| 江油市| 龙里县| 黄龙县|