python | 閉包


python | 閉包

基礎

作用域

作用域是程序運行時變量可被訪問的范圍,定義在函數內的變量是局部變量,局部變量的作用范圍只能是函數內部范圍內,它不能在函數外引用。
定義在模塊最外層的變量是全局變量,它是全局范圍內可見的,當然在函數里面也可以讀取到全局變量的。例如:

num = 10 # 全局變量
def foo():
    print(num)  # 10

而在函數外部則不可以訪問局部變量。

def foo():
    num = 10
print(num)  # NameError: name 'num' is not defined

嵌套函數

定義在函數里面的函數稱之為嵌套函數(nested function)

def outer(): # outer是外層函數
    msg = "python"

    def inner(): # inner 為內層函數即嵌套函數
        print(msg)

    return inner()

outer() # 輸出 python

對於嵌套函數,它可以訪問到其外層作用域中聲明的非局部(non-local)變量。首先查找本層函數 inner 內部是否有定義,沒有發現后開始查找外層作用域的變量

msg = "global"

def outer(): # outer是外層函數
    # msg = "python"

    def inner(): # inner 為內層函數即嵌套函數
        print(msg)

    return inner()

outer()

而當把 outer函數的變量注釋后,在全局進行定義,此時就開始查找全局變量

python 中函數是可以作為變量進行引用的,類似高中數學中的 f(x)計算
在高中數學復合函數定義中:

y=f(u), u=g(x),則函數 y=f(g(x))為復合函數,f(u)為外層函數,g(x)為內層函數,u為中間變量

計算順序應當是先計算內層函數然后結果作為變量來計算外層函數

閉包

def outer():  # outer是外層函數
    msg = "python"

    def inner():  # inner 為內層函數即嵌套函數
        print(msg)

    return inner # 返回 inner 的地址


result = outer()
result() # 輸出 python
print(outer()) # 輸出 inner的內存地址
print(outer()()) # 輸出 python和 None
print(result.func_closure)

結果

python
<function outer.<locals>.inner at 0x103136ea0>
python
None

閉包使得局部變量在函數外被訪問成為可能。 return 的函數不加括號返回的是地址。func_closure打印了閉包中包含了哪些外部變量。
enter description here

每個函數都有__closure__屬性,如果一個函數是閉包的話則會返回一個由 cell 對象組成的元組對象。而 cell 對象的cell_contents屬性就是閉包中保存的自由變量

def adder(x):
    def wrapper(y):
        return x + y
    return wrapper # 返回函數地址
adder5 = adder(5)

adder5(10) # 輸出 10
adder5(6) # 輸出 11
print(adder.__closure__)
print(adder5.__closure__)
print(adder5.__closure__[0].cell_contents)

結果

None
(<cell at 0x106430fd8: int object at 0x1050cf110>,)
5 # 自由變量

閉包特點

一個函數返回的函數對象,這個函數對象執行的話依賴非函數內部的變量值,這個時候,函數返回的實際內容如下:

  1. 函數對象
  2. 函數對象需要使用的外部變量和變量值
    以上就是閉包

閉包必須嵌套在一個函數里,必須返回一個調用外部變量的函數對象,才是閉包

最后推薦一個python 可視化運行的網站,對於 python 執行的步驟和存儲的變量等很直觀
http://www.pythontutor.com/visualize.html#mode=display

參考:
https://www.cnblogs.com/xiaxiaoxu/p/9785687.html
https://zhuanlan.zhihu.com/p/26934085


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM