天天看点

Python 类属性和对象属性

摘自:http://python.jobbole.com/85100/

示例:

class AAA():  
    aaa = 10  
 
# 情形1   
obj1 = AAA()  
obj2 = AAA()   
print obj1.aaa, obj2.aaa, AAA.aaa
 
# 情形2  
obj1.aaa += 2  
print obj1.aaa, obj2.aaa, AAA.aaa
 
# 情形3  
AAA.aaa += 3  
print obj1.aaa, obj2.aaa, AAA.aaa
           
结果:

    情形1: 10 10 10

    情形2: 12 10 10

    情形3: 12 13 13
           

Python中类属性的含义

Python属于动态强类型的语言,在很多地方和

C++/Java

这种静态语言不同,因此,不能把静态语言的规则套到动态语言上来。其中,类属性就是一个很好的例子。

类属性相当于Java中的 static 变量:public static String aaa = ""

Python中属性的获取

对于属性,我们通常采用类.属性或实例.属性的形式调用。

例如上例中的

AAA.aaa

属于类.属性形式,

obj1.aaa

属于实例.属性的形式

Python中属性的设置

对于属性的设置我们通常采用 类.属性 = 值或 实例.属性 = 值的形式

例如

obj1.aaa = 3

上例中

obj1.aaa += 2

等价于

obj1.aaa = obj1.aaa + 2

,这句话包含了属性获取及属性设置两个操作

OK,重点来了,Python中属性的获取和设置的机制与静态语言是不同的,正是背后机制的不同,导致了Python中类属性不一定是为其实例所共享的

Python中属性查找机制

Python中属性的获取存在一个向上查找机制,还是拿上面的例子做说明:

Python中一切皆对象,

AAA

属于类对象,

obj1

属于实例对象,从对象的角度来看,

AAA

obj1

是两个无关的对象,但是,Python通过下面的查找树建立了类对象

AAA

与实例对象

obj1

obj2

之间的关系。

AAA
         |
       -----
      |     |  
    obj1   obj2
           

当调用

AAA.aaa

时,直接从

AAA

获取其属性

aaa

但是情形1中调用

obj1.aaa

时,Python按照从

obj1

AAA

的顺序由下到上查找属性

aaa

值得注意的这时候

obj1

是没有属性

aaa

的,于是,Python到类

AAA

中去查找,成功找到,并显示出来。所以,从现象上来看,

AAA

的属性

aaa

确实是共享给其所有实例的,虽然这里只是从查找树的形式模拟了其关系。

Python中的属性设置

原帖子的作者也指出问题的关键在于情形2中

obj1.aaa += 2

为什么呢?

上面我们指出

obj.aaa += 2

包含了属性获取及属性设置两个操作。即

obj1.aaa += 2

等价于

obj1.aaa = obj1.aaa + 2

其中等式右侧的

obj.aaa

属于属性获取,其规则是按照上面提到的查找规则进行,即,这时候,获取到的是

AAA

的属性

aaa

,所以等式左侧的值为

12

第二个操作是属性设置,即

obj.aaa = 12

。当发生属性设置的时候,

obj1

这个实例对象没有属性

aaa

,因此会为自身动态添加一个属性

aaa

由于从对象的角度,类对象和实例对象属于两个独立的对象,所以,这个

aaa

属性只属于

obj1

,也就是说,这时候类对象

AAA

和实例对象

aaa

各自有一个属性

aaa

那么,在情形3中,再次调用

obj1.aaa

时,按照属性调用查找规则,这个时候获取到的是实例对象

obj1

的属性

aaa

,而不是类对象

AAA

的属性

aaa

对问题探讨的总结

到这里就可以完满解释上面的问题:

1. Python中属性的获取是按照从下到上的顺序来查找属性;

2. Python中的类和实例是两个完全独立的对象;

3. Python中的属性设置是针对对象本身进行的;

对情形1的解释

因为Python中的属性获取是按照从下到上的顺序来查找的,所以在情形1:

1 2 obj1 = AAA ( )    obj2 = AAA ( )

实例对象

obj1

obj2

不存在属性

aaa

证明如下:

1 2 3 4 >>> obj1 . __dict_ _ { } >>> obj2 . __dict_ _ { }

所以,此时,

obj1.aaa, obj2.aaa, AAA.aaa

实质上都是指

AAA.aaa

。因此,输出同样的结果。

对情形2的解释

因为Python中的类和实例是两个完全独立的对象且Python中的属性设置是针对对象本身进行的,所以在情形2:

1 obj1 . aaa += 2   

实质上是对实例对象

obj1

设置了属性

aaa

,并赋值为

12

。证明如下:

1 2 3 4 5 >>> obj1 . aaa = 3 >>> obj1 . __dict_ _ { 'aaa' : 3 } >>> obj2 . __dict_ _ { }

因此,再次调用

obj1.aaa

时,将获取到的是实例对象

obj1

的属性

aaa

,而不是类对象

AAA

的属性

aaa

。而对于实例对象

obj2

,由于其并没有属性

aaa

,所以调用

obj2.aaa

时,获取到的是

AAA

的属性

aaa

对情形3的解释

顺利理解了前两个情形,那么第3个情形就很容易了,改变

AAA

的属性

aaa

只能影响到类对象

AAA

和实例对象

obj2

,不能影响

obj1

,因为,

obj1

存在

aaa

,在获取时,不会获取到

AAA

的属性。