成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專(zhuān)欄INFORMATION COLUMN

Python: 攜帶狀態(tài)的閉包

daryl / 1052人閱讀

閉包

在 Python 中,函數(shù)也是一個(gè)對(duì)象。因此,我們?cè)诙x函數(shù)時(shí),可以再嵌套定義一個(gè)函數(shù),并將該嵌套函數(shù)返回,比如:

from math import pow

def make_pow(n):
    def inner_func(x):     # 嵌套定義了 inner_func
        return pow(x, n)   # 注意這里引用了外部函數(shù)的 n
    return inner_func      # 返回 inner_func

上面的代碼中,函數(shù) make_pow 里面又定義了一個(gè)內(nèi)部函數(shù) inner_func,然后將該函數(shù)返回。因此,我們可以使用 make_pow 來(lái)生成另一個(gè)函數(shù):

>>> pow2 = make_pow(2)  # pow2 是一個(gè)函數(shù),參數(shù) 2 是一個(gè)自由變量
>>> pow2

>>> pow2(6)
36.0

我們還注意到,內(nèi)部函數(shù) inner_func 引用了外部函數(shù) make_pow 的自由變量 n,這也就意味著,當(dāng)函數(shù) make_pow 的生命周期結(jié)束之后,n 這個(gè)變量依然會(huì)保存在 inner_func 中,它被 inner_func 所引用。

>>> del make_pow         # 刪除 make_pow
>>> pow3 = make_pow(3)
Traceback (most recent call last):
  File "", line 1, in 
NameError: name "make_pow" is not defined
>>> pow2(9)     # pow2 仍可正常調(diào)用,自由變量 2 仍保存在 pow2 中
81.0

像上面這種情況,一個(gè)函數(shù)返回了一個(gè)內(nèi)部函數(shù),該內(nèi)部函數(shù)引用了外部函數(shù)的相關(guān)參數(shù)和變量,我們把該返回的內(nèi)部函數(shù)稱(chēng)為閉包(Closure)。

在上面的例子中,inner_func 就是一個(gè)閉包,它引用了自由變量 n。

閉包的作用

閉包的最大特點(diǎn)就是引用了自由變量,即使生成閉包的環(huán)境已經(jīng)釋放,閉包仍然存在;

閉包在運(yùn)行時(shí)可以有多個(gè)實(shí)例,即使傳入的參數(shù)相同,比如:

>>> pow_a = make_pow(2)
>>> pow_b = make_pow(2)
>>> pow_a == pow_b
False

利用閉包,我們還可以模擬類(lèi)的實(shí)例。

這里構(gòu)造一個(gè)類(lèi),用于求一個(gè)點(diǎn)到另一個(gè)點(diǎn)的距離:

from math import sqrt

class Point(object):
    def __init__(self, x, y):
        self.x, self.y = x, y

    def get_distance(self, u, v):
        distance = sqrt((self.x - u) ** 2 + (self.y - v) ** 2)
        return distance

>>> pt = Point(7, 2)        # 創(chuàng)建一個(gè)點(diǎn)
>>> pt.get_distance(10, 6)  # 求到另一個(gè)點(diǎn)的距離
5.0

用閉包來(lái)實(shí)現(xiàn):

def point(x, y):
    def get_distance(u, v):
        return sqrt((x - u) ** 2 + (y - v) ** 2)

    return get_distance

>>> pt = point(7, 2)
>>> pt(10, 6)
5.0

可以看到,結(jié)果是一樣的,但使用閉包實(shí)現(xiàn)比使用類(lèi)更加簡(jiǎn)潔。

常見(jiàn)誤區(qū)

閉包的概念很簡(jiǎn)單,但實(shí)現(xiàn)起來(lái)卻容易出現(xiàn)一些誤區(qū),比如下面的例子:

def count():
    funcs = []
    for i in [1, 2, 3]:
        def f():
            return i
        funcs.append(f)
    return funcs

在該例子中,我們?cè)诿看?for 循環(huán)中創(chuàng)建了一個(gè)函數(shù),并將它存到 funcs 中。現(xiàn)在,調(diào)用上面的函數(shù),你可能認(rèn)為返回結(jié)果是 1, 2, 3,事實(shí)上卻不是:

>>> f1, f2, f3 = count()
>>> f1()
3
>>> f2()
3
>>> f3()
3

為什么呢?原因在于上面的函數(shù) f 引用了變量 i,但函數(shù) f 并非立刻執(zhí)行,當(dāng) for 循環(huán)結(jié)束時(shí),此時(shí)變量 i 的值是3,funcs 里面的函數(shù)引用的變量都是 3,最終結(jié)果也就全為 3。

因此,我們應(yīng)盡量避免在閉包中引用循環(huán)變量,或者后續(xù)會(huì)發(fā)生變化的變量。

那上面這種情況應(yīng)該怎么解決呢?我們可以再創(chuàng)建一個(gè)函數(shù),并將循環(huán)變量的值傳給該函數(shù),如下:

def count():
    funcs = []
    for i in [1, 2, 3]:
        def g(param):
            f = lambda : param    # 這里創(chuàng)建了一個(gè)匿名函數(shù)
            return f
        funcs.append(g(i))        # 將循環(huán)變量的值傳給 g
    return funcs

>>> f1, f2, f3 = count()
>>> f1()
1
>>> f2()
2
>>> f3()
3
小結(jié)

閉包是攜帶自由變量的函數(shù),即使創(chuàng)建閉包的外部函數(shù)的生命周期結(jié)束了,閉包所引用的自由變量仍會(huì)存在。

閉包在運(yùn)行可以有多個(gè)實(shí)例。

盡量不要在閉包中引用循環(huán)變量,或者后續(xù)會(huì)發(fā)生變化的變量。

本文由 funhacks 發(fā)表于個(gè)人博客,采用 Creative Commons BY-NC-ND 4.0(自由轉(zhuǎn)載-保持署名-非商用-禁止演繹)協(xié)議發(fā)布。
非商業(yè)轉(zhuǎn)載請(qǐng)注明作者及出處。商業(yè)轉(zhuǎn)載請(qǐng)聯(lián)系作者本人。
本文標(biāo)題為: Python: 攜帶狀態(tài)的閉包
本文鏈接為: https://funhacks.net/2016/11/...

參考資料

返回函數(shù) - 廖雪峰的官方網(wǎng)站

Why aren"t python nested functions called closures? - Stack Overflow

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/44262.html

相關(guān)文章

  • python基礎(chǔ)知識(shí)之函數(shù)初階——閉包

    摘要:我們說(shuō)觸發(fā)了閉包的函數(shù)叫做閉包函數(shù)閉包最大的特點(diǎn)就是它可以被外層函數(shù)返回后賦值給一個(gè)變量,并且攜帶了外層函數(shù)內(nèi)定義的變量例子如下變量為函數(shù)開(kāi)辟的局部命名空間內(nèi)定義的變量函數(shù)內(nèi)引用了變量的內(nèi)層函數(shù)名被當(dāng)作返回值,此時(shí)閉包規(guī)則達(dá)成。 什么是閉包? 其實(shí)我們?cè)谑褂煤瘮?shù)過(guò)程中不經(jīng)意間就會(huì)觸發(fā)閉包,因?yàn)榭倳?huì)出于某種原因會(huì)在函數(shù)內(nèi)引用或修改上一層函數(shù)的變量,這時(shí)就會(huì)觸發(fā)閉包 那么什么是閉包?其實(shí)就...

    TIGERB 評(píng)論0 收藏0
  • 開(kāi)個(gè)腦洞,如何使用 javascript 實(shí)現(xiàn)“仿函數(shù)”(Functor)?

    摘要:中的函數(shù)本身就是對(duì)象,可以攜帶自身狀態(tài),另外還有化等函數(shù)式編程的方法讓函數(shù)緩存狀態(tài),基本上沒(méi)有仿函數(shù)存在的必要。 Functor 仿函數(shù)(Functor)是 C++ 里面一個(gè)重要的概念,簡(jiǎn)而言之就是使用重載了 operator() 運(yùn)算符的對(duì)象模仿函數(shù)的行為,帶來(lái)的收益是仿函數(shù)可以攜帶自身狀態(tài),普通的 C++ 函數(shù)不是對(duì)象,做不到這一點(diǎn)。 js 中的函數(shù)本身就是對(duì)象,可以攜帶自身狀態(tài),...

    anRui 評(píng)論0 收藏0
  • python中關(guān)于閉包用法詳解

      小編寫(xiě)這篇文章的主要目的,主要是來(lái)給大家介紹,關(guān)于python中,相關(guān)語(yǔ)法問(wèn)題的解答,比如在python,我們會(huì)遇到閉包和裝飾器不會(huì)用的情況,那么,下文就會(huì)來(lái)給大家做一個(gè)詳細(xì)的解答?! ?args與**kwarsg及閉包和裝飾器  過(guò)程  先理解閉包,再理解裝飾器,不要忘了不定長(zhǎng)參數(shù) deffunc():   msg='111'   deffunc1():   print(ms...

    89542767 評(píng)論0 收藏0
  • 《JavaScript語(yǔ)言精粹》 代碼摘錄

    摘要:最近在讀這本評(píng)價(jià)頗高的語(yǔ)言精粹,其作者是的創(chuàng)造者,在業(yè)界頗有名氣。 最近在讀這本評(píng)價(jià)頗高的《JavaScript語(yǔ)言精粹》,其作者Douglas Crockford 是JSON的創(chuàng)造者,在業(yè)界頗有名氣。以下是閱讀過(guò)程中認(rèn)為比較有用的摘錄的代碼,希望能對(duì)各位有所啟發(fā) 自定義的method方法 Function.prototype.method = function(name,func...

    haitiancoder 評(píng)論0 收藏0
  • 學(xué)習(xí)筆記:JavaScript 閉包是怎么通過(guò)作用域鏈霸占更多內(nèi)存

    摘要:閉包是怎么通過(guò)作用域鏈霸占更多內(nèi)存的本文是作者學(xué)習(xí)高級(jí)程序設(shè)計(jì)第一小節(jié)的一點(diǎn)個(gè)人理解,詳細(xì)教程請(qǐng)參考原教材。函數(shù)執(zhí)行過(guò)程創(chuàng)建了一個(gè)函數(shù)的活動(dòng)對(duì)象,作用域鏈的最前端指向這個(gè)對(duì)象。函數(shù)執(zhí)行完畢返回值后執(zhí)行環(huán)境作用域鏈和活動(dòng)對(duì)象一并銷(xiāo)毀。 JavaScript 閉包是怎么通過(guò)作用域鏈霸占更多內(nèi)存的? 本文是作者學(xué)習(xí)《JavaScript 高級(jí)程序設(shè)計(jì)》7.2第一小節(jié)的一點(diǎn)個(gè)人理解,詳細(xì)教程請(qǐng)...

    HmyBmny 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

最新活動(dòng)
閱讀需要支付1元查看
<