大家都知道面向對象的三大特性:封裝,繼承,多态。封裝特性在上一章節已經講解過。這一章節主要講解繼承和多态。
繼承:
當定義一個類的時候,可以從現有的類進行繼承。那麼新定義的類可以稱為子類,被繼承的現有的類稱為基類,父類或者超類。
上一章節大家應該有所注意以下代碼:
>>> class Animal(object):
pass
object類是python所有類的基類,Animal類是object類的子類。Animal類繼承于object類。
繼承到底有什麼好處?舉個例子:
>>> class Animal(object):
def call(self):
print('Animal is calling!')
>>> class dog(Animal):
pass
>>> dog = dog()
>>> dog.call()
Animal is calling!
dog類繼承了Animal類,當聲明了一個dog執行個體對象後,可以直接調用父類Animal的call方法。
這就是繼承的好處,能夠直接繼承來自父類的屬性和方法,然後直接調用。這樣就精簡了代碼,提高了代碼的複用性。
如果父類在執行個體化對象的時候,要預設傳入name參數的話,子類dog繼承的時,應該怎麼辦?
例子:
>>> class Animal(object):
def __init__(self,name):
self.name = name
def call(self):
print ('Animal is calling!')
>>> class dog(Animal):
def __init__(self,name,birth):
super(dog,self).__init__(name)//大家注意這句代碼
self.birth = birth
def call(self):
print ('dog is calling!')
>>> dog = dog('wangcai','2016-8-5')
>>> print dog.name
wangcai
>>> print dog.birth
2016-8-5
函數super(dog, self)将傳回目前類繼承的父類,即Animal,然後調用__init__()方法,注意self參數已在super()中傳入,在__init__()中将隐式傳遞,不需要寫出(也不能寫).
大家發現,dog子類也定義了一個call方法。那麼執行個體化dog對象,dog.call()會發生什麼?
多态
>>> dog.call()
dog is calling!
當子類和父類都存在相同的
call()
方法時,我們說,子類的
call()
覆寫了父類的
call()
,在代碼運作的時候,總是會調用子類的
call()
。類似于C++的虛函數或者java的抽象方法。
在了解多态之前,要判斷一個對象/變量是否屬于某一個類/類型,使用isinstance方法。
>>> class Animal(object):
def call(self):
print('Animal is calling!')
>>> class dog(Animal):
def call(self):
print('dog is calling!')
>>> d =dog()
>>> a =Animal()
>>> isinstance(d,Animal)
True
>>> isinstance(a,dog)
False
看來,d不僅僅是dog,而且還是animal。而a 雖然是animal,但是不一定是dog,也有可能是cat。是以isinstance(a,dog)傳回為false。
是以在繼承關系中,如果一個執行個體的資料類型是某個子類,那麼它的資料類型也可以被看做是父類。是以isinstance(d,Animal)傳回為True。
有個上述的了解,那麼我們再舉個例子。
>>> def lound_call(animal):
animal.call()
>>> lound_call(dog())
dog is calling!
>>> lound_call(Animal())
Animal is calling!
新增一個Animal子類cat。
>>> class Cat(Animal):
def call(self):
print('cat is calling!')
>>> lound_call(Cat())
cat is calling!
你會發現,新增一個
Animal
的子類,不必對lound_call
()
做任何修改,實際上,任何依賴
Animal
作為參數的函數或者方法都可以不加修改地正常運作,原因就在于多态。
多态的好處就是,當我們需要傳入
Dog
、
Cat
……時,我們隻需要接收
Animal
類型就可以了,因為
Dog
Cat
……都是
Animal
類型,然後,按照
Animal
類型進行操作即可。由于
Animal
類型有
call()
方法,是以,傳入的任意類型,隻要是
Animal
類或者子類,就會自動調用實際類型的
call()
方法,這就是多态的意思:
對于一個變量,隻需要知道它是
Animal
類型,無需确切地知道它的子類型,就可以放心地調用
call()
方法,而具體調用的
call()
方法是作用在
Animal
Dog
Cat
對象上,由運作時該對象的确切類型決定,這就是多态真正的威力:調用方隻管調用,不管細節,而當我們新增一種
Animal
的子類時,隻要確定
call()
方法編寫正确,不用管原來的代碼是如何調用的。這就是著名的“開閉”原則:
對擴充開放:允許新增
Animal
子類;
對修改封閉:不需要修改依賴
Animal
類型的
lound_call()
等函數。
小結:這一章節主要講解了python面向對象的屬性繼承和多态。