LOAD_DEREF
是 Python 字節碼指令,它與閉包和嵌套函數有關。要理解 LOAD_DEREF
,我們首先需要了解 Python 中的幾個概念:cell
、free variable
和閉包。
-
Cell 和 Free Variables:
當一個嵌套函數引用了其上級作用域中的一個變量,但該變量并不是全局的或局部的,那么這個變量就被稱為free variable
。cell
是一個內部機制,用于存儲這些free variables
,使嵌套函數可以訪問它們,即使上級函數已經退出。 -
閉包 (Closure):
在 Python 中,函數是一等對象,這意味著它們可以作為參數傳遞,可以返回,可以定義在另一個函數內部等。當內部函數引用了外部函數的變量時,我們得到了一個閉包。閉包捕獲并保存了外部函數的free variables
,使得這些變量即使在外部函數結束后仍然可以被訪問。
LOAD_DEREF
指令就是在閉包中使用的,用于加載從一個 cell
或 free variable
中的值到棧上。具體來說,它用于加載由 cell
或嵌套函數作用域中的局部變量表示的值。
讓我們看一個簡單的示例:
def outer(x):def inner():return xreturn innerfunc = outer(10)
print(func()) # 輸出: 10
在上述示例中,inner
函數是一個閉包,因為它引用了外部函數 outer
的變量 x
。當我們調用 outer
并返回 inner
時,變量 x
的值仍然被保存下來,這就是通過 cell
機制實現的。當 inner
函數執行并嘗試訪問 x
時,就會使用 LOAD_DEREF
指令。
如果你查看 inner
函數的字節碼,你會看到 LOAD_DEREF
指令。這可以通過以下方式完成:
import dis
dis.dis(func)
在如下輸出中,我們看到 LOAD_DEREF
指令,表示它正在從一個 cell
或 free variable
加載一個值。
6 0 LOAD_DEREF 0 (x)2 RETURN_VALUE
接下來,讓我們看看 free variable
和 cell
的例子。
-
Free Variable:
free variable
是一個在嵌套函數內部被引用,但不是這個嵌套函數的局部變量,也不是全局變量的變量。在以下示例中,x
就是一個free variable
對于inner
函數來說。def outer():x = 10 # 這里的 x 就是一個 free variable 對于 inner 來說def inner():print(x) # x 在這里被引用,但它既不是 inner 的局部變量,也不是一個全局變量inner()outer() # 輸出: 10
-
Cell:
當我們談論閉包時,Python 使用
cell
對象來實現這個特性。這是因為,盡管上層函數已經執行完畢并退出了,但嵌套的函數依然可以訪問上層函數的變量。這就是通過將這些變量保存在cell
對象中來實現的。在以下示例中,我們創建了一個閉包,然后使用
__closure__
屬性來查看這些cell
對象:def outer(x):def inner():return xreturn innerclosure_function = outer(25) print(closure_function()) # 輸出: 25# 查看 closure_function 的 cell 對象 cell = closure_function.__closure__[0] print(cell.cell_contents) # 輸出: 25
cell
對象有一個屬性cell_contents
,它保存了閉包中被引用的變量的當前值。在上面的例子中,cell.cell_contents
的值是25
,這是我們傳遞給outer
函數的值。【注】:print(closure_function._ _closure _ _) 的輸出為 (<cell at 0x00000223E8C3A6B0: int object at 0x00000223E8AD03F0>,)