为什么是数字类型删除和列表类型不,当他们是属性的类实例(被删除)?



在下面的代码示例中,我希望ab在每个循环结束时都被删除。

结果是a被删除了,而b没有被删除。为什么呢?我如何确保b在每个循环结束时也被删除?

class bag: 
a = 5
b = []

def funcie(self): 
self.a = self.a + 1  
self.b.append(1)

for i in range(5): 
inst = bag()
inst.funcie()
print(inst.a)
print(inst.b)
# del inst

输出:

6
[1]
6
[1, 1]
6
[1, 1, 1]
6
[1, 1, 1, 1]
6
[1, 1, 1, 1, 1]
编辑:所以这篇文章解释了为什么b列表在每个循环中不断增长,即我应该在__init(self)__函数中声明b列表。然而,它并没有解释为什么a变量在每个循环结束时被覆盖,而b变量却没有。

bag.a(一个类属性)没有被覆盖,它被a(一个实例属性)遮蔽,特别是inst

Python的一般规则是,如果没有内部/阴影作用域隐藏,则读取将从外部/阴影作用域读取。内部/隐藏作用域是通过赋值创建的,而不仅仅是突变(这只是从变量中读取,然后要求它改变自己)。在作用域和属性的工作方式之间有一些微妙的区别,所以我将只关注属性(因为这是您所询问的)。

当您在bag的新实例上执行self.a = self.a + 1时,您读取的self.a来自class属性,但是在写入self.a时,您创建了一个新的阴影实例属性。类属性(bag.a == 5)仍然存在,并且没有被修改,但是从实例的角度来看,它只看到实例属性(inst.a == 6)。如果您添加了print(bag.a),您将看到它从未更改。

相比之下,self.b.append(1)读取类属性并要求它就地修改自己,这将改变绑定到类属性本身的对象。

如果希望修改类属性而不创建实例属性,则必须对类本身进行操作。例如,您可以更改:
self.a = self.a + 1

:

type(self).a = self.a + 1  # Or type(self).a = type(self).a + 1

或者更简单地使用+=来避免重复更复杂的内容:

type(self).a += 1

数字与list的不同之处在于Python使用它们的值并将计算结果存储在新的位置。因此,a = a+1的结果每次都存储在内存中的不同位置。列表保持在相同的内存位置,并在适当的位置更新。以下代码:

class bag: 
a = 5
b = []

def funcie(self): 
self.a += 1  
self.b.append(1)
inst = bag()
print("bag memory ids:     ", id(bag.a), id(bag.b))
print("inst memory ids:    ", id(inst.a), id(inst.b))
inst.funcie()
print("ids after 1x funcie:", id(inst.a), id(inst.b))
inst.funcie()
print("ids after 2x funcie:", id(inst.a), id(inst.b))

有这样的输出,您可以看到inst.a的id发生了变化,而inst.b的id保持不变:

bag memory ids:      9789120 139707042123328
inst memory ids:     9789120 139707042123328
ids after 1x funcie: 9789152 139707042123328
ids after 2x funcie: 9789184 139707042123328

因此,a的更新值存储在不同的位置,而不改变原始值。

相关内容

  • 没有找到相关文章

最新更新