日本免费高清视频-国产福利视频导航-黄色在线播放国产-天天操天天操天天操天天操|www.shdianci.com

學無先后,達者為師

網站首頁 編程語言 正文

Python閉包與閉包陷阱舉例詳解_python

作者:專注算法的馬里奧學長 ? 更新時間: 2023-03-21 編程語言

1 什么是閉包

在 Python 中,閉包是一種特殊的函數,它能夠記住它所在的環境(也稱作上下文)。這意味著閉包能夠訪問定義它的作用域中的變量。閉包通常用于封裝數據和提供對外部訪問的接口。

在 Python 中使用閉包有以下幾點好處:

  • 保存狀態:閉包可以保存外部函數的狀態,以便在內部函數中使用。
  • 簡化代碼:閉包可以簡化代碼結構,使得復雜的邏輯變得簡單易懂。
  • 模塊化編程:閉包可以更好地封裝代碼,提高代碼的可重用性。
  • 保證函數線程安全:閉包可以保證函數的線程安全性,避免全局變量被多線程修改。

2 閉包示例代碼

代碼示例如下:

def outer_func(x):
    def inner_func(y):
        return x + y
    return inner_func

closure = outer_func(10)
print(closure(5)) # 15

這是一個閉包的示例代碼,其中outer_func是外部函數,它返回一個內部函數inner_func。內部函數使用了外部函數的變量x,并且在被調用時使用了參數y。因此,當我們調用outer_func(10)時,它返回了一個閉包(即inner_func),它記錄了x=10的值。之后,我們可以調用這個閉包,并傳入參數y來計算結果。

3 什么是閉包陷阱

Python中的閉包陷阱指的是在閉包中引用了變量時,如果該變量在閉包外部被修改,則閉包內部的值也會改變。這可能會導致程序的錯誤或意外行為。

4 閉包陷阱代碼實例

請對比以下兩組代碼

4.1 第一組代碼實例

def closure1():
    l = []
    for i in range(3):
        def inner(i_=i):
            return i_**2
        l.append(inner)
    return l


l1 = closure1()
print([i() for i in l1])

在執行代碼時,首先i的在range(3)中獲取的值為0,接下來執行l.append(inner)。這里inner并沒有括號,所以inner本身不會被執行,而是在l中添加了一個inner函數對象。并且inner函數的形參i_默認值為0。

接下來,在for循環的作用下,l又被重復添加了兩次inner對象,其中i_的默認值分別為1和2。

執行完closure1后,我們使用列表推到式去遍歷l1

列表推導式中的i()使得inner對象被執行。因為i()中未傳入任何參數,所以其中的i_使用了我們定義的默認參數:0,1,2。在執行完inner函數后,這些數字變成了0,1,4。因此最終的輸出即為[0,1,4] 。

以上是一段正常的非閉包代碼。

4.2 第二組代碼實例

def closure2():
    l = []
    for i in range(3):
        def inner():
            return i**2
        l.append(inner)
    print(inner.__closure__)
    return l


l2 = closure2()
print([i() for i in l2])

這一組代碼和上面一組代碼沒有很大的區別,唯一的差異是,這一組代碼的inner并未傳入形參i_。inner中的i直接取自外部。
因此,在執行closure2中的for循環時,l中依然會被傳入3個inner函數對象,唯一的區別是傳入的對象沒有指定形參的默認值。
在執行[i() for i in l2]這個列表推到式時,inner函數并未找到對i的賦值,因此回到外部的closure2中去尋找,并找到了i的值為3。
因此,對于這段代碼,每一個inner函數對象的輸出都是4。

很明顯這并不是我們想要的結果,這就是一個典型的閉包陷阱。

總結

原文鏈接:https://blog.csdn.net/nkufang/article/details/128759484

欄目分類
最近更新