91超碰碰碰碰久久久久久综合_超碰av人澡人澡人澡人澡人掠_国产黄大片在线观看画质优化_txt小说免费全本

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

Python 閉包

發布時間:2020-07-28 08:31:48 來源:網絡 閱讀:652 作者:騎士救兵 欄目:編程語言

閉包

如果在一個內部函數里,對在外部作用域(但不是在全局作用域)的變量進行引用,那么內部函數就被認為是閉包(closure)

這里是一個閉包的例子:

def addx(x):
    def adder(y):
        return x + y
    return adder

if __name__ == '__main__':
    func = addx(10)
    print(func(1))
    print(func(2))
    print(func(3))

執行結果:

11
12
13

這里例子里,adder(y) 就是一個內部函數。它里面引用了外部的變量x,x是外部作用域addx(x)里的變量,但是不是全局變量。所以內部的adder(y)是一個閉包。
精煉一些:閉包=函數塊+定義函數時的環境。adder就是函數塊,x就是環境。

閉包的注意事項

作用域的問題

這個例子里應該是一個函數的作用域的問題,和閉包沒太大關系:

def foo():
    x = 0
    def f():
        x = 1
        return x
    print(x)  # 0
    print(f())  # 1
    print(x)  # 0

if __name__ == '__main__':
    foo()

內部函數和外部函數都定義了變量x。這里內部沒有引用外部的變量x,還是生成了一個自己的局部變量,也叫x,這個變量還外部的函數的x變量是沒有關系的。所以這里的問題只是一個作用域的問題。

操作外部變量

下面的這個函數是有問題的,語法有錯誤:

def squares():
    x = 0

    def f():
        x = x + 1
        return x * x
    return f

看似符合閉包的要求,但是標量x出現在了賦值符號 '=' 的左邊。python規則指定所有在賦值語句左面的變量都是局部變量。這里因為x被認為是局部變量,然后再執行x+1的時候就只會在局部里找這個x的值,但是找不到,所以就報錯了,錯誤信息如下:

UnboundLocalError: local variable 'x' referenced before assignment

解決方案1
避免直接引用外部,如果引用的是外部的列表、字典等。那么變量名就不會直接出現在賦值符號左邊了:

def squares():
    x = [0]

    def f():
        x[0] = x[0] + 1
        return x[0] * x[0]
    return f

如果直接要引用的是外部的列表、字典這類變量,用就不會遇到這類問題。但是這里例子里,這么做感覺也不好

解決方案2
如果要引用的外部變量就是一個簡單的數值或者字符串,雖然上面的方法可行,但是還有更好的做法。
使用 nonlocal 聲明,把內層的局部變量設置成外層局部可用,但是還不是全局的。類似聲明全局變量的 global 的用法。這里主要是因為python里不需要像其他語言里,有類型的var之類的關鍵字來聲明變量。變量直接賦值就完成了聲明,平時用起來很方便,但是在這里,因為在操作的時候變量直接出現在賦值符號左邊了,就會被認為新定義了一個局部變量了。
完整的示例:

def squares():
    x = 0

    def f():
        nonlocal x
        x = x + 1
        return x * x
    return f

if __name__ == '__main__':
    func = squares()
    print(func())
    print(func())
    print(func())

閉包的作用

閉包主要是在函數式開發過程中使用。下面介紹的兩種使用場景,用面向對象也是可以很簡單的實現的。但是在用Python進行函數式編程時,閉包對數據的持久化以及按配置產生不同的功能,是很有幫助的。

讓函數還可以擁有狀態

當閉包執行完后,仍然能夠保持住當前的運行環境。上面也提過了:閉包=函數塊+定義函數時的環境。這個環境可以在閉包里改變,并且保持下去。
下面是一個類似移動棋子的例子。先在坐標0,0創建棋子。然后可以用內部函數移動棋子。移動后,棋子的狀態也更新了,下次再移動棋子,就是在之前的位置的基礎上再進行的移動:

def create_piece():
    x = 0
    y = 0

    def move(offset_x=0, offset_y=0):
        nonlocal x, y
        x += offset_x
        y += offset_y
        return x, y
    return move

if __name__ == '__main__':
    player = create_piece()  # 這里是不是和面向對象里的使用前,生成對象的實例很像?
    print(player())  # 打印當前坐標
    player(1, 1)  # 移動棋子
    print(player())  # 打印當前坐標
    print(player(1, 3))  # 再移動棋子并打印坐標

配置函數的參數

閉包可以根據外部作用域的局部變量來得到不同的結果,這有點像一種類似配置功能的作用,我們可以修改外部的變量,閉包根據這個變量展現出不同的功能。
下面的例子,統計字符串里,某個特定的字符出現了多少次。要統計哪個字符,就生成一個對應的閉包,生成的時候把參數傳入:

def count_letter(a):
    def count(s):
        x = 0
        for i in s:
            if i == a:
                x += 1
        return x
    return count

if __name__ == '__main__':
    s = 'Hello World !!!'
    count_l = count_letter('l')
    count_space = count_letter(' ')
    print(count_l(s))
    print(count_space(s))

這個用處也是可以用面向對象方便的解決的。相當于生成實例的時候給構造函數傳入不同的值。

總結

面向對象里把閉包的這點作用都覆蓋了,所以貌似不會也沒什么。主要是為了支持函數式編程使用的。

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

宁陵县| 客服| 安陆市| 和龙市| 天峨县| 饶阳县| 胶州市| 华安县| 林州市| 柳河县| 肇源县| 杭锦后旗| 克什克腾旗| 商河县| 靖边县| 汉川市| 德江县| 屯门区| 虎林市| 文山县| 新龙县| 南投县| 邢台市| 新安县| 大丰市| 天台县| 奉化市| 柏乡县| 辛集市| 云龙县| 浦城县| 靖安县| 黑山县| 施甸县| 蒙山县| 萍乡市| 鄯善县| 揭阳市| 彰武县| 福州市| 麻城市|