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 x
return inner
func = 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 x
return inner
closure_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 _ _) 的输出为 (