類與執行個體
類與執行個體相互關聯著:類是對象的定義,而執行個體是“真正的實物”,它存放了類中所定義的對象的具體資訊。
下面的樣本展示了如何建立一個類:
class MyNewObjectType(bases): ''' 建立 MyNewObjectType 類''' class_suite
關鍵字是 class,緊接著一個類名。隨後是定義類的類代碼。這裡通常由各種各樣的定義和聲明組成。新式類和經典類聲明的最大不同在於,所有新式類必須繼承至少一個父類,參數 bases 可以是一個(單繼承)或多個(多重繼承)用於繼承的父類。
建立一個執行個體的過程稱作執行個體化,過程如下(注意:沒有使用 new 關鍵字):
myFirstObject = MyNewObjectType()
類名使用我們所熟悉的函數操作符(()),以“函數調用”的形式出現。然後你通常會把這個建立的執行個體賦給一個變數。賦值在文法上不是必須的,但如果你沒有把這個執行個體儲存到一個變數中,它就沒用了,會被自動垃圾收集器回收,因為任何引用指向這個執行個體。這樣,你剛剛所做的一切,就是為那個執行個體分配了一塊記憶體,隨即又釋放了它。
類既可以很簡單,也可以很複雜,這全憑你的需要。最簡單的情況,類僅用作名稱空間(namespace)。這意味著你把資料儲存在變數中,對他們按名稱空間進行分組,使得他們處於同樣的關係空間中——所謂的關係是使用標準 Python 句點屬性標識。例如,你有一個本身沒有任何屬性的類,使用它僅對資料提供一個名字空間,讓你的類擁有像 C 語言中的結構體(structure)一樣的特性,或者換句話說,這樣的類僅作為容器物件來共用名稱字空間。
樣本如下:
class MyData(object): passmathObj = MyData()mathObj.x = 4mathObj.y = 5mathObj.x + mathObj.y9mathObj.x \\* mathObj.y20
方法
在 Python 中,方法定義在類定義中,但只能被執行個體所調用。也就是說,調用一個方法的最終途徑必須是這樣的:(1)定義類(和方法);(2)建立一個執行個體;(3)最後一步,用這個執行個體調用方法。例如:
class MyDataWithMethod(object): # 定義類 def printFoo(self): # 定義方法 print 'You invoked printFoo()!'
這裡的 self 參數,它在所有的方法聲明中都存在。這個參數代表執行個體對象本身,當你用執行個體調用方法時,由解譯器傳遞給方法的,所以,你不需要自己傳遞 self 進來,因為它是自動傳入的。
舉例說明一下,假如你有一個帶兩參數的方法,所有你的調用只需要傳遞第二個參數。
下面是執行個體化這個類,並調用那個方法:
> > > myObj = MyDataWithMethod()> > > myObj.printFoo()You invoked printFoo()!
\\_init\\(),是一個特殊的方法。在 Python 中, \\init\\() 實際上不是一個構造器。你沒有調用“new”來建立一個新對象。(Python 根本就沒有“new”這個關鍵字)。取而代之, Python 建立執行個體後,在執行個體化過程中,調用 \\init\\_()方法,當一個類被執行個體化時,就可以定義額外的行為,比如,設定初始值或者運行一些初步診斷代碼——主要是在執行個體被建立後,執行個體化調用返回這個執行個體之前,去執行某些特定的任務或設定。
建立一個類(類定義)
class AddrBookEntry(object): '''address book entry class''' def __init__(self, nm, ph): # 定義構造器 self.name = nm # 設定 name self.phone = ph # 設定 phone print 'Created instance for:', self.name def updatePhone(self, newph): # 定義方法 self.phone = newph print 'Updated phone# for: ', self.name
在 AddrBookEntry 類的定義中,定義了兩個方法: \\_init\\()和updatePhone()。\\init\\()在執行個體化時被調用,即,在AddrBookEntry()被調用時。你可以認為執行個體化是對 \\init\\()的一種隱式的調用,因為傳給AddrBookEntry()的參數完全與\\init\\_()接收到的參數是一樣的(除了self,它是自動傳遞的)。
建立執行個體(執行個體化)
> > > john = AddrBookEntry('John Doe', '408-555-1212') # 為 John Doe 建立執行個體> > > jane = AddrBookEntry('Jane Doe', '650-555-1212') # 為 Jane Doe 建立執行個體
這就是執行個體化調用,它會自動調用 \\_init\\()。 self 把執行個體對象自動傳入\\init\\_()。
另外,如果不存在預設的參數,那麼傳給 \\_init\\_() 的兩個參數在執行個體化時是必須的。
訪問執行個體屬性
> > > john> > > john.name> > > jane.name> > > jane.phone
一旦執行個體被建立後,就可以證實一下,在執行個體化過程中,我們的執行個體屬性是否確實被 \\_init\\_() 設定了。我們可以通過解譯器“轉儲”執行個體來查看它是什麼類型的對象。
方法調用(通過執行個體)
> > > john.updatePhone('415-555-1212') # 更新 John Doe 的電話> > > john.phone
updatePhone()方法需要一個參數(不計 self 在內):新的電話號碼。在 updatePhone()之後,立即檢查執行個體屬性,可以證實已生效。
方法與屬性的小結
直接上代碼,已經在裡面有注釋了
#coding:utf8name = 'yangyanxing'class Test(): class kevin(): var1 = '我是內部類' name = 'kvein' gae = '26' def fun1(self): print self.name print '我是公用方法' self.__fun2() #可以通過公有就去來調用私人方法,在調用的過程中可以變更 def __fun2(self): print '我是私人方法' @classmethod def fun3(self): #可以不通過執行個體來訪問這個類方法 print '#'*40 print self.name print '我是類方法' @staticmethod #靜態方法,也是可以不通過執行個體對象就可以訪問的方法但是在定義的時候不用加self def fun4(): print Test.name print name #這裡的name是全域變數 Test.fun3() print '我是靜態方法'print Test.name #公有屬性可以直接方法,不用執行個體化對象yang = Test() #執行個體化一個類interyang = Test.kevin() #執行個體化一個內部類yang.fun1() #方法類裡面的公用屬性print interyang.var1 # 訪問內部類裡的屬性Test.fun3()#訪問類方法Test.fun4()#coding:utf8class Test(): var1 = '類的公有屬性' __var2 = '類的私人屬性' def fun(self): self.var2 = '對象的公有屬性' # 這裡定義了一個對象的公有屬性 self.__var3 = '對象的私人屬性'# 這裡定義了一個對象的私人屬性 var4 = '函數的局部變數' #這裡定義了一個函數的局部變數,這裡面的var4隻有在函數內部使用kevin = Test() #執行個體了一個對象yang = Test() #又執行個體了另外一個對象print kevin.var1##print kevin.__var2 #這裡將無法訪問kevin.fun()print kevin.var2 #在沒有調用fun函數之前是沒有var2的##print kevin.__var3 對象的私人屬性是無法調用的##print yang.var2 #這裡因為沒有調用yang的fun方法,所以還是無法訪問yang裡的var2
建立子類
靠繼承來進行子類化是建立和定製新類型的一種方式,新的類將保持已存在類所有的特性,而不會改動原來類的定義。對於新類類型而言,這個新的子類可以定製只屬於它的特定功能。除了與父類或基類的關係外,子類與通常的類沒有什麼區別,也像一般類一樣進行執行個體化。注意下面,子類聲明中提到了父類:
class EmplAddrBookEntry(AddrBookEntry): '''Employee Address Book Entry class''' # 員工地址簿類 def __init__(self, nm, ph, id, em): AddrBookEntry.__init__(self, nm, ph) self.empid = id self.email = em def updateEmail(self, newem): self.email = newem print 'Updated e-mail address for:', self.name
現在我們建立了第一個子類, EmplAddrBookEntry。 Python 中,當一個類被派生出來,子類就繼承了基類的屬性,所以,在上面的類中,我們不僅定義了 \\_init\\_(),UpdateEmail()方法,而且 EmplAddrBookEntry 還從 AddrBookEntry 中繼承了 updatePhone()方法。
如果需要,每個子類最好定義它自己的構造器,不然,基類的構造器會被調用。然而,如果子類重寫基類的構造器,基類的構造器就不會被自動調用了——這樣,基類的構造器就必須顯式寫出才會被執行,就像我們上面那樣,用AddrBookEntry.\\_init\\_()設定名字和電話號碼。我們的子類在構造器後面幾行還設定了另外兩個執行個體屬性:員工ID和電子郵件地址。
注意,這裡我們要顯式傳遞 self 執行個體對象給基類構造器,因為我們不是在該執行個體中而是在一個子類執行個體中調用那個方法。因為我們不是通過執行個體來調用它,這種未綁定的方法調用需要傳遞一個適當的執行個體(self)給方法。
使用子類
> > > john = EmplAddrBookEntry('John Doe', '408-555-1212', 42, 'john@spam.doe')> > > john> > > john.name> > > john.phone> > > john.email> > > john.updatePhone('415-555-1212')> > > john.phone> > > john.updateEmail('john@doe.spam')> > > john.email