类变量和实例变量之间的区别

May*_*ain 4 python oop class

我已经在Stack Exchange上阅读了很多像Python一样的答案- 为什么在课堂上使用"self"? 阅读完这些内容之后,我了解到实例变量对于类的每个实例都是唯一的,而类变量是在所有实例之间共享的.在玩的时候我发现这个代码 -

class A:
    x = []
    def add(self):
        self.x.append(1)

x = A()
y = A()
x.add()
print "Y's x:",y.x
Run Code Online (Sandbox Code Playgroud)

确实给出了输出[1].但是,这段代码 -

class A:
    x = 10
    def add(self):
        self.x += 1

x = A()
y = A()
x.add()

print "Y's x:",y.x
Run Code Online (Sandbox Code Playgroud)

给出输出,就像10我认为的那样11.如果这是一个非常无聊的问题,请原谅我,但我在编程方面不是很有经验.

mil*_*ose 10

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

这意味着,在您的第二个示例中,您执行以下操作:

self.x += 1
Run Code Online (Sandbox Code Playgroud)

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

self.x = self.x + 1
Run Code Online (Sandbox Code Playgroud)

Python的作用是:

  1. 查一查self.x.此时,self没有实例属性x,因此A.x找到了具有值的class属性10.
  2. 对RHS进行评估,得出结果11.
  3. 这一结果被分配到一个新的实例属性xself.

所以在下面,当你查找时x.x,你会得到这个新的实例属性add().查找时y.x,您仍然可以获得class属性.要更改class属性,必须A.x += 1显式使用- 只有在读取属性值时才会进行查找.


您的第一个示例是经典问题,并且您不应将类属性用作实例属性的"默认"值.你打电话的时候:

self.x.append(1)
Run Code Online (Sandbox Code Playgroud)

没有任务可以self.x进行.(更改可变对象的内容,如a list,与赋值不同.)因此,没有添加新的实例属性x会影响它,查找x.xy.x稍后会给出类属性中的相同列表.


注意:在Python中,x += y并不总是等同于x = x + y.Python允许您将类型的正常运算符与正常运算符分开覆盖.这对于可变对象大多有意义,其中就地版本将直接更改内容而无需重新分配表达式的LHS.但是,不可变对象(例如第二个示例中的数字)不会覆盖就地运算符.在这种情况下,语句会被评估为常规添加和重新分配,解释您看到的行为.

(我从这个SO答案中解除了上述内容,请查看更多细节.)