我已经在Stack Exchange上阅读了许多答案,如Python - why use "self" in a class? 阅读完这些内容之后,我了解到实例变量对于类的每个实例都是唯一的,而类变量是在所有实例之间共享的。 在玩的时候我发现了这段代码 -
class A:
x = []
def add(self):
self.x.append(1)
x = A()
y = A()
x.add()
print "Y's x:",y.x
确实给出了输出[1]
。但是,这段代码 -
class A:
x = 10
def add(self):
self.x += 1
x = A()
y = A()
x.add()
print "Y's x:",y.x
在我看来,将输出设为10
,应该是11
。
如果这是一个很无聊的问题,请原谅我,但我在编程方面不是很有经验。
答案 0 :(得分:10)
类变量按实例属性阴影。这意味着在查找属性时,Python首先查看实例,然后查看类。此外,在对象上设置变量(例如self
)总是会创建一个实例变量 - 它永远不会更改类变量。
这意味着,在第二个示例中,您执行以下操作:
self.x += 1
(在这种情况下,见脚注)相当于:
self.x = self.x + 1
Python的作用是:
self.x
。此时,self
没有实例属性x
,因此找到了类属性A.x
,其值为10
。11
。x
的新实例属性self
。在下面,当您查找x.x
时,您将获得在add()
中创建的新实例属性。查找y.x
时,您仍然可以获得class属性。要更改class属性,您必须显式使用A.x += 1
- 只有在读取属性值时才会进行查找。
您的第一个示例是经典问题,并且您不应将类属性用作实例属性的“默认”值。当你打电话:
self.x.append(1)
没有self.x
发生任务。 (更改可变对象的内容,如list
,与赋值不同。)因此,没有新的实例属性添加到x
会影响它,稍后查找x.x
和y.x
会为您提供类属性中的相同列表。
注意:在Python中,x += y
并不总是等同于x = x + y
。 Python允许您将类型的正常运算符与正常运算符分开覆盖。这对于 mutable 对象来说很有意义,其中就地版本将直接更改内容,而不会重新分配表达式的LHS。但是,不可变对象(例如第二个示例中的数字)不会覆盖就地运算符。在这种情况下,语句会被评估为常规添加和重新分配,解释您看到的行为。
(我从this SO answer解除了上述内容,请查看更多详情。)