问题描述
我有一个关于“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)
当我们运行它时会发生什么?首先,我们初始化 array
和 path
以保存对空列表的引用:
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 的引用。