我已经在 Stack Exchange 上阅读了很多答案,例如 Python - why use "self" in a class? 阅读这些答案后,我了解到实例变量对于类的每个实例都是唯一的,而类变量在所有实例之间共享。
在玩游戏时,我发现这段代码给出了输出[1]
:
class A:
x = []
def add(self):
self.x.append(1)
x = A()
y = A()
x.add()
print "Y's x: ", y.x
然而,这段代码给出了 10
作为输出,而在我看来它应该是 11
:
class A:
x = 10
def add(self):
self.x += 1
x = A()
y = A()
x.add()
print "Y's x: ", y.x
为什么 A
类变量在我运行 x.add()
时没有更新?我在编程方面不是很有经验,所以请原谅。
最佳答案
类变量被实例属性隐藏。这意味着在查找属性时,Python 首先在实例中查找,然后在类中查找。此外,在对象上设置变量(例如 self
)总是会创建一个实例变量 - 它永远不会更改类变量。
这意味着当您在第二个示例中执行以下操作时:
self.x += 1
这(在本例中,请参见脚注)等同于:
self.x = self.x + 1
Python 所做的是:
- 查找
self.x
。此时,self
没有实例属性x
,因此找到了类属性A.x
,其值为10
。 - 计算 RHS,给出结果
11
。 - 此结果分配给
self
的新实例属性x
。
因此在下面,当您查找 x.x
时,您将获得在 add()
中创建的这个新实例属性。在查找 y.x
时,您仍然可以获得类属性。要更改类属性,您必须显式使用 A.x += 1
- 查找仅在读取属性值时发生。
您的第一个 示例是一个典型的陷阱,也是您不应将类属性用作实例属性的“默认”值的原因。当你打电话时:
self.x.append(1)
没有对 self.x
进行赋值。 (更改可变对象的内容,如列表
,与赋值不同。)因此,没有新的实例属性添加到x
会隐藏它,稍后查找 x.x
和 y.x
会为您提供来自类属性的相同列表。
注意:在 Python 中,x += y
并不总是等同于 x = x + y
。 Python 允许您分别覆盖类型的就地运算符和普通运算符。这主要适用于可变 对象,其中就地版本将直接更改内容,无需 重新分配表达式的 LHS。但是,不可变 对象(例如第二个示例中的数字)不会覆盖就地运算符。在这种情况下,该语句确实会被评估为常规添加和重新分配,从而解释您看到的行为。
(我从 this SO answer 中提取了上面的内容,有关更多详细信息,请参阅此处。)
关于python - 类变量和实例变量的区别,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/19753897/