2016-12-13 116 views
0

我对下面的Python行为感到莫名其妙。为什么第二个和第三个实例(b,c,i)的属性是类属性ia的行为有所不同?为什么更改实例变量也会改变静态变量?

In [47]: class Foo: 
    ...:  i=0 
    ...: 

In [48]: a = Foo() 

In [49]: a.i = 1 

In [50]: a.i 
Out[50]: 1 

In [51]: Foo.i 
Out[51]: 0 

In [52]: b = Foo() 

In [53]: b.i 
Out[53]: 0 

In [54]: Foo.i is b.i 
Out[54]: True 

In [55]: Foo.i is a.i 
Out[55]: False 

In [56]: c = Foo() 

In [57]: Foo.i is c.i 
Out[57]: True 
+1

慎用解释的'int值int'的结果... Python的缓存小整数。虽然在这种情况下,我认为这不会影响你的演示,但也许最好使用一个虚拟类来进行演示。 –

回答

6

这是发生了什么事。当你这样做:

a.i = 1 

你使用一个名称创建一个实例变量,阴影类属性。 class属性仍然存在,但:

>>> class Foo: 
...  i = 0 
...  
>>> a = Foo() 
>>> Foo.i 
0 
>>> a.i = 69 
>>> a.i 
69 
>>> a.__class__.i 
0 
>>> del a.i # deletes the instance attribute, resolving lookup on class 
>>> a.i 
0 

要了解住在实例的命名空间中,检查出的实例字典:

>>> a = Foo() 
>>> a.__dict__ 
{} 
>>> a.i = 1 
>>> a.__dict__ 
{'i': 1} 
0

a.i = 1不会改变Foo.i你打算。它相当于分配了一个实例成员a。如果您看到a.__dict__b.__dict__,则非常清楚。

In [11]: a.__dict__ 
Out[11]: {'i': 1} 

In [13]: b.__dict__ 
Out[13]: {} 

如果你想真的改变类成员变量,你应该使用Foo.i = 1。这将影响所有Foo实例。同样,它在Foo.__dict__上非常清楚。

In [17]: Foo.__dict__ 
Out[17]: 
mappingproxy({'__dict__': <attribute '__dict__' of 'Foo' objects>, 
       '__doc__': None, 
       '__module__': '__main__', 
       '__weakref__': <attribute '__weakref__' of 'Foo' objects>, 
       'i': 0})