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

时间:2013-11-03 14:14:10

标签: python class oop

我已经在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。 如果这是一个很无聊的问题,请原谅我,但我在编程方面不是很有经验。

1 个答案:

答案 0 :(得分:10)

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

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

self.x += 1

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

self.x = self.x + 1

Python的作用是:

  1. 查找self.x。此时,self没有实例属性x,因此找到了类属性A.x,其值为10
  2. 评估RHS,得出​​结果11
  3. 此结果已分配给x的新实例属性self
  4. 在下面,当您查找x.x时,您将获得在add()中创建的新实例属性。查找y.x时,您仍然可以获得class属性。要更改class属性,您必须显式使用A.x += 1 - 只有在读取属性值时才会进行查找。


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

    self.x.append(1)
    

    没有self.x发生任务。 (更改可变对象的内容,如list,与赋值不同。)因此,没有新的实例属性添加到x会影响它,稍后查找x.xy.x会为您提供类属性中的相同列表。


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

    (我从this SO answer解除了上述内容,请查看更多详情。)