Python 面向對象編程(一)
雖然Python是解釋性語言,但是它是面向對象的,能夠進行對象編程。下面就來了解一下如何在Python中進行對象編程。
一.如何定義一個類
在進行python面向對象編程之前,先來了解幾個術語:類,類對象,實例對象,屬性,函數和方法。
類是對現實世界中一些事物的封裝,定義一個類可以采用下面的方式來定義:
class className: block
注意類名后面有個冒號,在block塊里面就可以定義屬性和方法了。當一個類定義完之后,就產生了一個類對象。類對象支持兩種操作:引用和實例化。引用操作是通過類對象去調用類中的屬性或者方法,而實例化是產生出一個類對象的實例,稱作實例對象。比如定義了一個people類:
class people: name = 'jack' #定義了一個屬性 #定義了一個方法 def printName(self): print self.name
people類定義完成之后就產生了一個全局的類對象,可以通過類對象來訪問類中的屬性和方法了。當通過people.name(至於為什么可以直接這樣訪問屬性后面再解釋,這里只要理解類對象這個概念就行了)來訪問時,people.name中的people稱為類對象,這點和C++中的有所不同。當然還可以進行實例化操作,p=people( ),這樣就產生了一個people的實例對象,此時也可以通過實例對象p來訪問屬性或者方法了(p.name).
理解了類、類對象和實例對象的區別之后,我們來了解一下Python中屬性、方法和函數的區別。
在上面代碼中注釋的很清楚了,name是一個屬性,printName( )是一個方法,與某個對象進行綁定的函數稱作為方法。一般在類里面定義的函數與類對象或者實例對象綁定了,所以稱作為方法;而在類外定義的函數一般沒有同對象進行綁定,就稱為函數。
二.屬性
在類中我們可以定義一些屬性,比如:
class people: name = 'jack' age = 12 p = people() print p.name,p.age
定義了一個people類,里面定義了name和age屬性,默認值分別為'jack'和12。在定義了類之后,就可以用來產生實例化對象了,這句p = people( )實例化了一個對象p,然后就可以通過p來讀取屬性了。這里的name和age都是公有的,可以直接在類外通過對象名訪問,如果想定義成私有的,則需在前面加2個下划線 ' __'。
class people: __name = 'jack' __age = 12 p = people() print p.__name,p.__age
這段程序運行會報錯:
提示找不到該屬性,因為私有屬性是不能夠在類外通過對象名來進行訪問的。在Python中沒有像C++中public和private這些關鍵字來區別公有屬性和私有屬性,它是以屬性命名方式來區分,如果在屬性名前面加了2個下划線'__',則表明該屬性是私有屬性,否則為公有屬性(方法也是一樣,方法名前面加了2個下划線的話表示該方法是私有的,否則為公有的)。
三.方法
在類中可以根據需要定義一些方法,定義方法采用def關鍵字,在類中定義的方法至少會有一個參數,,一般以名為'self'的變量作為該參數(用其他名稱也可以),而且需要作為第一個參數。下面看個例子:
class people: __name = 'jack' __age = 12 def getName(self): return self.__name def getAge(self): return self.__age p = people() print p.getName(),p.getAge()
如果對self不好理解的話,可以把它當做C++中類里面的this指針一樣理解,就是對象自身的意思,在用某個對象調用該方法時,就將該對象作為第一個參數傳遞給self。
四.類中內置的方法
在Python中有一些內置的方法,這些方法命名都有比較特殊的地方(其方法名以2個下划線開始然后以2個下划線結束)。類中最常用的就是構造方法和析構方法。
構造方法__init__(self,....)在生成對象時調用,可以用來進行一些初始化操作,不需要顯示去調用,系統會默認去執行。構造方法支持重載,如果用戶自己沒有重新定義構造方法,系統就自動執行默認的構造方法。
析構方法__del__(self)在釋放對象時調用,支持重載,可以在里面進行一些釋放資源的操作,不需要顯示調用。
還有其他的一些內置方法:
比如 __cmp__( ), __len( )__等,具體的用法可以參考這篇博文:
http://www.cnblogs.com/simayixin/archive/2011/05/04/2036295.html
五.類屬性、實例屬性、類方法、實例方法以及靜態方法
在了解了類基本的東西之后,下面看一下python中這幾個概念的區別。
先來談一下類屬性和實例屬性
在前面的例子中我們接觸到的就是類屬性,顧名思義,類屬性就是類對象所擁有的屬性,它被所有類對象的實例對象所共有,在內存中只存在一個副本,這個和C++中類的靜態成員變量有點類似。對於公有的類屬性,在類外可以通過類對象和實例對象訪問。
class people: name = 'jack' #公有的類屬性 __age = 12 #私有的類屬性 p = people() print p.name #正確 print people.name #正確 print p.__age #錯誤,不能在類外通過實例對象訪問私有的類屬性 print people.__age #錯誤,不能在類外通過類對象訪問私有的類屬性
實例屬性是不需要在類中顯示定義的,比如:
class people: name = 'jack' p = people() p.age =12 print p.name #正確 print p.age #正確 print people.name #正確 print people.age #錯誤
在類外對類對象people進行實例化之后,產生了一個實例對象p,然后p.age = 12這句給p添加了一個實例屬性age,賦值為12。這個實例屬性是實例對象p所特有的,注意,類對象people並不擁有它(所以不能通過類對象來訪問這個age屬性)。當然還可以在實例化對象的時候給age賦值。
class people: name = 'jack' #__init__()是內置的構造方法,在實例化對象時自動調用 def __init__(self,age): self.age = age p = people(12) print p.name #正確 print p.age #正確 print people.name #正確 print people.age #錯誤
如果需要在類外修改類屬性,必須通過類對象去引用然后進行修改。如果通過實例對象去引用,會產生一個同名的實例屬性,這種方式修改的是實例屬性,不會影響到類屬性,並且之后如果通過實例對象去引用該名稱的屬性,實例屬性會強制屏蔽掉類屬性,即引用的是實例屬性,除非刪除了該實例屬性。
class people: country = 'china' print people.country p = people() print p.country p.country = 'japan' print p.country #實例屬性會屏蔽掉同名的類屬性 print people.country del p.country #刪除實例屬性 print p.country
下面來看一下類方法、實例方法和靜態方法的區別。
類方法:是類對象所擁有的方法,需要用修飾器"@classmethod"來標識其為類方法,對於類方法,第一個參數必須是類對象,一般以"cls"作為第一個參數(當然可以用其他名稱的變量作為其第一個參數,但是大部分人都習慣以'cls'作為第一個參數的名字,就最好用'cls'了),能夠通過實例對象和類對象去訪問。
class people: country = 'china' #類方法,用classmethod來進行修飾 @classmethod def getCountry(cls): return cls.country p = people() print p.getCountry() #可以用過實例對象引用 print people.getCountry() #可以通過類對象引用
類方法還有一個用途就是可以對類屬性進行修改:
class people: country = 'china' #類方法,用classmethod來進行修飾 @classmethod def getCountry(cls): return cls.country @classmethod def setCountry(cls,country): cls.country = country p = people() print p.getCountry() #可以用過實例對象引用 print people.getCountry() #可以通過類對象引用 p.setCountry('japan') print p.getCountry() print people.getCountry()
運行結果:
結果顯示在用類方法對類屬性修改之后,通過類對象和實例對象訪問都發生了改變。
實例方法:在類中最常定義的成員方法,它至少有一個參數並且必須以實例對象作為其第一個參數,一般以名為'self'的變量作為第一個參數(當然可以以其他名稱的變量作為第一個參數)。在類外實例方法只能通過實例對象去調用,不能通過其他方式去調用。
class people: country = 'china' #實例方法 def getCountry(self): return self.country p = people() print p.getCountry() #正確,可以用過實例對象引用 print people.getCountry() #錯誤,不能通過類對象引用實例方法
靜態方法:需要通過修飾器"@staticmethod"來進行修飾,靜態方法不需要多定義參數。
class people: country = 'china' @staticmethod #靜態方法 def getCountry(): return people.country print people.getCountry()
對於類屬性和實例屬性,如果在類方法中引用某個屬性,該屬性必定是類屬性,而如果在實例方法中引用某個屬性(不作更改),並且存在同名的類屬性,此時若實例對象有該名稱的實例屬性,則實例屬性會屏蔽類屬性,即引用的是實例屬性,若實例對象沒有該名稱的實例屬性,則引用的是類屬性;如果在實例方法更改某個屬性,並且存在同名的類屬性,此時若實例對象有該名稱的實例屬性,則修改的是實例屬性,若實例對象沒有該名稱的實例屬性,則會創建一個同名稱的實例屬性。想要修改類屬性,如果在類外,可以通過類對象修改,如果在類里面,只有在類方法中進行修改。
從類方法和實例方法以及靜態方法的定義形式就可以看出來,類方法的第一個參數是類對象cls,那么通過cls引用的必定是類對象的屬性和方法;而實例方法的第一個參數是實例對象self,那么通過self引用的可能是類屬性、也有可能是實例屬性(這個需要具體分析),不過在存在相同名稱的類屬性和實例屬性的情況下,實例屬性優先級更高。靜態方法中不需要額外定義參數,因此在靜態方法中引用類屬性的話,必須通過類對象來引用。
關於面向對象編程暫時就講這么多了,其他關於類的繼承和方法重載這些內容將在后面繼續講解。