2013-11-03 168 views
3

我已经在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

感谢@mbatchkarov,我不知道我是怎么让那个滑:) – MayankJain

回答

9

通过实例属性,类变量是被遮蔽的。这意味着查找属性时,Python首先查找实例,然后查找该类。此外,在对象上设置变量(例如self)总是会创建一个实例变量 - 它永远不会更改类变量。

这意味着当在你的第二例如,你做的事:

self.x += 1 

这是(在这种情况下,见注),相当于:

self.x = self.x + 1 

什么Python做的是:

  1. 查找self.x。此时,self没有实例属性x,因此找到类属性A.x,值为10
  2. 对RHS进行评估,得出结果11
  3. 此结果被分配给self的新实例属性x

因此,当您查找x.x时,会得到在add()中创建的新实例属性。在查找y.x时,您仍然可以获得类属性。要更改类属性,您必须明确使用A.x += 1 - 只有在读取属性值时才会查找。


第一例子是一个经典的疑难杂症和“默认”值实例的属性,你不应该使用类的原因属性。当您致电:

self.x.append(1) 

没有指定self.x发生。 (改变内容的可变对象的,像list,是不一样的分配。)因此,没有新的实例属性添加到x会遮盖了,后来就找了x.xy.x给你同样的来自class属性的列表。


注:在Python,x += y并不总是等同于x = x + y。 Python允许您为一个类型重写与正常运算符分开的原地运算符。这主要是有道理的,可变对象,其中就地版本将直接改变内容表达的LHS的重新分配。然而,不变对象(如在你的第二个例子数)不会覆盖就地运营商。在这种情况下,该声明确实会被评估为常规添加和重新分配,从而解释您所看到的行为。

(我解除了上述从this SO answer,看到有更多的细节。)

+0

很好的解释! – aIKid

+0

其实,'x + = ...'并不总是等同于'x = x + ...'。你可以看到,如果你用list类variabel修改代码,使用'self.x + = [1]',而不是'self.x.append(1)'。 – delnan

+0

我狡辩一点关于'X + = y'是大致相当于'X = X + y'; '__iadd__'和'__add__'是不同的。 – DSM