国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專欄INFORMATION COLUMN

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

daryl / 1048人閱讀

閉包

在 Python 中,函數(shù)也是一個對象。因此,我們在定義函數(shù)時,可以再嵌套定義一個函數(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 里面又定義了一個內(nèi)部函數(shù) inner_func,然后將該函數(shù)返回。因此,我們可以使用 make_pow 來生成另一個函數(shù):

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

>>> pow2(6)
36.0

我們還注意到,內(nèi)部函數(shù) inner_func 引用了外部函數(shù) make_pow 的自由變量 n,這也就意味著,當(dāng)函數(shù) make_pow 的生命周期結(jié)束之后,n 這個變量依然會保存在 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

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

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

閉包的作用

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

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

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

利用閉包,我們還可以模擬類的實例。

這里構(gòu)造一個類,用于求一個點到另一個點的距離:

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)建一個點
>>> pt.get_distance(10, 6)  # 求到另一個點的距離
5.0

用閉包來實現(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é)果是一樣的,但使用閉包實現(xiàn)比使用類更加簡潔。

常見誤區(qū)

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

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

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

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

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

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

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

def count():
    funcs = []
    for i in [1, 2, 3]:
        def g(param):
            f = lambda : param    # 這里創(chuàng)建了一個匿名函數(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án)變量,或者后續(xù)會發(fā)生變化的變量。

本文由 funhacks 發(fā)表于個人博客,采用 Creative Commons BY-NC-ND 4.0(自由轉(zhuǎn)載-保持署名-非商用-禁止演繹)協(xié)議發(fā)布。
非商業(yè)轉(zhuǎn)載請注明作者及出處。商業(yè)轉(zhuǎn)載請聯(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)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請注明本文地址:http://m.specialneedsforspecialkids.com/yun/44262.html

相關(guān)文章

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

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

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

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

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

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

    89542767 評論0 收藏0
  • 《JavaScript語言精粹》 代碼摘錄

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

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

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

    HmyBmny 評論0 收藏0

發(fā)表評論

0條評論

最新活動
閱讀需要支付1元查看
<