Python 绑定关闭后期绑定

问题描述

我有一个关于“python 绑定” 的问题(假设这个问题与此有关)。我在下面的问题上花了几个小时,并达到了关闭延迟绑定”“范围”主题

据我所知,“闭包”被定义为一个包含自由变量的函数,它是后期绑定。所以,我理解下面的代码输出 [[0,1],[0,1]] 而不是 [[0],1]]。

# expected [[0],1]] but got [[0,1]]
# this is because of "closure late binding"
def my_func():
    array.append(path)
    return

array,path = [],[]
for value in range(2):
    path.append(value)
    my_func()

print(array)

因此,我尝试设置如下参数以避免自由变量,进而关闭。我的预期输出是 [[0],1]] 但仍然是 [[0,1]] 尽管函数中没有自由变量。

# expected [[0],1]]
# this function is not a closure as far as I kNow
def my_func(array,path):
    array.append(path)
    return

array,[]
for value in range(2):
    path.append(value)
    my_func(array,path)

print(array)

我是否遗漏了一些基本的东西,比如应用于任何函数的后期绑定?

解决方法

这与其说是关于闭包,还不如说是关于变量在 Python 中的工作方式(这与它们在许多其他语言(如 Lisp 和 Java)中的工作方式没有什么不同)。

变量不是一个可以放置值的盒子,它是一个保存对象引用的盒子。同样,列表中的每一项都是对一个值的引用。

让我们看看您的第二个程序。因为 my_func 并没有真正做任何事情,我们可以通过内联它来简化一点,如下所示:

array,path = [],[]
for value in range(2):
    path.append(value)
    array.append(path)

print(array)

当我们运行它时会发生什么?首先,我们初始化 arraypath 以保存对空列表的引用:

array --> []
path  --> []

然后我们开始运行循环,并执行path.append(0)。现在看起来像这样:

array --> []

path  --> [*]
           |
           v
           0

然后我们将 path 所指的任何东西——即包含对“零”对象的引用的列表对象——附加到 array

array --> [*]
           |
           v
path  --> [*]
           |
           v
           0

然后我们运行循环的下一次迭代,在 path 引用的列表中追加一个:

array --> [*]
           |
           v
path  --> [*,*]
           |  |
           v  v
           0  1

最后,我们再次将相同的列表附加到array

array --> [*,*]
           | /
           |
           v
path  --> [*,*]
           |  |
           v  v
           0  1

因此,当我们完成时,array 持有对列表的引用,而该列表又持有对一个列表的两个引用,该列表持有对整数 0 和 1 的引用。