天天看點

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

的屬性。