摘自: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
的屬性。