Python 字节码指令 LOAD_DEREF

LOAD_DEREF 是 Python 字节码指令,它与闭包和嵌套函数有关。要理解 LOAD_DEREF,我们首先需要了解 Python 中的几个概念:cellfree variable 和闭包。

  1. Cell 和 Free Variables:
    当一个嵌套函数引用了其上级作用域中的一个变量,但该变量并不是全局的或局部的,那么这个变量就被称为 free variablecell 是一个内部机制,用于存储这些 free variables,使嵌套函数可以访问它们,即使上级函数已经退出。

  2. 闭包 (Closure):
    在 Python 中,函数是一等对象,这意味着它们可以作为参数传递,可以返回,可以定义在另一个函数内部等。当内部函数引用了外部函数的变量时,我们得到了一个闭包。闭包捕获并保存了外部函数的 free variables,使得这些变量即使在外部函数结束后仍然可以被访问。

LOAD_DEREF 指令就是在闭包中使用的,用于加载从一个 cellfree 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 指令,表示它正在从一个 cellfree variable 加载一个值。

  6           0 LOAD_DEREF               0 (x)
              2 RETURN_VALUE

接下来,让我们看看 free variablecell 的例子。

  1. 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
    
  2. 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 _ _) 的输出为 (,)

你可能感兴趣的:(Python,python)