为什么对象属性中的存储函数会被覆盖(Python)



下面是我的问题的一个最低限度的工作示例,其中我有一个包含fish对象数组的school对象,我希望每个fish都有基于其索引的属性。我所做的就是设置属性,然后打印出来,无论是在初始化过程中,还是在类完全实例化后。问题是,设置这些属性似乎对函数无效。此外,它的性能也因是否使用枚举而不同(我想了解这一点(。

在下面的代码中,输出显示我的学校对象中fish的'func'属性被覆盖,但'x'属性没有。

class Fish:
def __init__(self):
self.x = -1
self.func = lambda y: -1

class School:
def __init__(self):
self.fishList = [Fish() for i in range(2)]
for fishIndex, f in enumerate(self.fishList):
f.x = fishIndex
f.func = lambda y: fishIndex
print("No enumerate:")
for f in self.fishList:
print(f.x, f.func(0))
print("Enumerate")
for fishIndex, f in enumerate(self.fishList):
print(f.x, f.func(0))
mySchool = School()
print("-----------------------------------------")
print("No enumerate:")
for f in mySchool.fishList:
print(f.x, f.func(0))
print("Enumerate:")
for fishIndex, f in enumerate(mySchool.fishList):
print(f.x, f.func(0))

输出:

No enumerate:
0 1
1 1
Enumerate
0 0
1 1
-----------------------------------------
No enumerate:
0 1
1 1
Enumerate:
0 1
1 1

到目前为止,我已经追踪到这个问题源于我如何储存鱼。如果我将fish单独存储,而不是存储在数组中,那么函数将正确地持久存在。因此,这让我认为这是一个可变性/指针问题。但如果是这种情况,我预计"x"也不会正确地持续存在。

编辑:为了澄清,在输出的第一个";枚举";在虚线之前是我对所有输出的期望。

func的定义中,fishIndex是一个自由变量。这意味着名称本身,而不是fishIndex的当前值,是函数定义的一部分。

当函数被调用时,它将使用__init__中定义的局部变量fishIndex的当前值。

__init__中,当您在for循环中将该变量用作索引变量时,该变量会发生变化。

__init__之外,fishIndex仍然引用__init__中定义的变量,即使该函数返回。我们说func是定义它的范围的变量上的闭包

在全局范围内重用循环中的名称fishIndex不会影响func的行为。

最新更新