python中類屬性和數據屬性的解釋


python中的類叫class object,類的實例叫instance object. 
類 Class Objects 
類擁有兩種操作,1.類屬性 attribute references 2.實例化instantiation 
類屬性就相當於專屬於一個類的變量(即某些語言中的類的靜態公共變量static public),使用方法是:類名稱.類屬性名稱 實例化則是創建一個類的實例的方法,使用方法是:類名稱() 
在使用實例化方法后,將會創建一個空的類實例,一般的python類的定義中會有一個特殊的方法來初始化,這個方法就是__init__(),當調用了類的實例化方法后,__init__()方法會立刻被這個類的實例調用.也就是說,__init__()不是構造函數,而是一個普通的方法. 類的實例 Instance Objects 
類的實例只擁有一種操作,這就是 1.屬性調用 attribute references. 
屬性調用指 1.數據屬性 2.方法 
數據屬性不需要預先定義!當數據屬性初次被使用時,它即被創建並賦值(they spring into existence when they are first assigned to) 看下面的例子 

class Test:
pass
t=Test()
t.name='notus'
print t.name


我們在類Test中並沒有定義name這個數據屬性,但是在代碼中卻可以直接使用,這就是數據屬性. 現在,拋開廣義上對屬性attribute的解釋,在實際編程中經常用的屬性這個詞,在python的class中有兩種屬性:類屬性,數據屬性.(大多數編程語言都有這樣兩種屬性).類屬性屬於類,數據屬性屬於類的實例.我們假設有類Test,則一般這兩種屬性的用法是 

Test.mode
t=Test()
t.name

那么這兩種屬性應該在什么時候定義呢? 
按照上面的討論可知,數據屬性不需要預先定義,當數據屬性初次被使用時,它即被創建並賦值.而實際上,類屬性也是如此. 
因此,我們有了下面的例子

class Test:
pass
t=Test()
t.name='notus'
print t.name
Test.mode='auto'
print Test.mode

大家看,數據屬性name和類屬性mode均沒有在類中被定義,你要做的,只是在需要的時候使用他們即可.如何預先給屬性賦值 
可以在類的定義中使用屬性,先看這個例子 

class Test:
def ask(theInstance):
theInstance.name='notus'
Test.mode='auto'
##print Test.mode
t=Test()
##print t.name
t.ask()
print Test.mode
print t.name

類Test有方法ask.注意看程序中被注釋掉的兩行,在沒有使用ask()方法前,運行被注釋的那兩句的任一句均會出錯,提示"class Test has no attribute ...".但運行ask()后,我們在ask()方法中初始了這兩個屬性 ,則運行通過. 
注意看ask()接收的參數theInstance,這個傳過來的就是程序中類Test的實例t .一般的命名規范建議將這個參數命名為self.這個參數是python自動傳入的,所以不需要再在程序中傳. 
如果想要在類實例化后立刻使用這些屬性,那就應該把這些屬性的初始放在__init__()方法中,前面說過了,__init__()方法在類的實例化結束后立刻被自動調用. 所以我們的例子程序可以改成這樣 

class Test:
def __init__(self):
self.name='notus'
Test.mode='auto'
##print Test.mode
t=Test()
##print t.name
print Test.mode
print t.name


所以可以有這樣的類定義 

class Test:
def __init__(self):
self.name='notus'
Test.mode='auto'
def ask(self):
self.date='2008'
##print Test.mode
t=Test()
##print t.name
print Test.mode
print t.name
##print t.date
t.ask()
print t.date


數據屬性date只有在調用了ask()方法后才可以被使用.當然這樣也可以使用這個屬性

##print Test.mode
t=Test()
##print t.name
print Test.mode
print t.name
t.date='2007'
print t.date


在程序中創建了date這個數據屬性.可以想象,之后調用ask()方法時,數據屬性date已經存在,只是被改變了值. 不用方法也可以初始化屬性 
看下面的示例程序 

class Test:
action='win the game'  #類屬性
print Test.action
t=Test()
print t.action
Test.action='at least 1 point'
print Test.action
print t.action
t.action='dont lose'
print Test.action
print t.action


運行的結果如下 

win the game 
win the game 
at least 1 point 
at least 1 point 
at least 1 point 
dont lose 
現象可以概括為:"改變類屬性,數據屬性跟着變,改變數據屬性,類屬性不變".

 
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 
對於上面這個結果,沒有任何懸念,通過兩個AAA的實例,以及通過AAA類名引用aaa屬性值,都是同樣的答案。 那在情形2中,應該是什么結果呢,我相信大多數人還是會說出正確的結果: 
12  10  10 
在上面這個結果中,一旦執行了obj1.aaa += 2,也就意味着obj1這個實例有了個實例的屬性值,他的屬性名稱也為aaa,那是不是obj1的aaa是個新的屬性呢,實際上可以說法是對,但也不對,實際上obj1.aaa += 2這個代碼的執行,並不像我們想象的那么簡單,首先他會到obj1所屬的類AAA的屬性列表中去找一個名稱為aaa的屬性,如果有,他就會返回該值作為 obj1中aaa的初始值,也就是說,這以后obj1.aaa的這個屬性值跟AAA.aaa就基本沒有關系了。 那在情形3中呢,答案是什么呢: 
12  13  13 
這又怎么說呢,其實很簡單,AAA.aaa對AAA類屬性做了一次設置,obj1.aaa經過一次+=操作后,實際上與AAA.aaa脫離了關系,而obj2.aaa沒有經過任何的屬性操作,因此其只會從其所屬的類AAA中去獲得aaa,並返回。 

引用 
《python核心編程》 
如果嘗試在實例中設定或更新類屬性會創建一個實例屬性 c.version,后者會阻止對類屬性 
C.versioin 的訪問,因為第一個訪問的就是 c.version,這樣可以對實例有效地“遮蔽”類屬性C.version,直到 c.version 被清除掉。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM