繼承與多型
一、繼承
繼承是一種建立新類的方式,在python中,新建的類可以繼承一個或者多個父類,新建的類可以稱為子類或者父類,被繼承的類可以稱為父類或者基類。
子類可以使用父類中的屬性或者方法
解決了類與類之間程式碼冗餘的問題
在python2當中,繼承了objcet類的子子孫孫類都稱為新式類,沒有繼承的都稱為經典類
在python3中,沒有區分經典類和新式類,都是新式類
單繼承
只繼承一個父類的被稱為單繼承
單繼承下的屬性查詢
class Foo(): def f2(self): print('from Foo') def f1(self): print('from Foo') class Bar(Foo): def f1(self): print('from f1') # 當該屬性或方法在子類中,則使用子類的,如果沒有則去父類中尋找,父類中也沒有就會報錯 obj = Bar() obj.f1() # from f1 obj.f2() # from Foo obj.f3() # 報錯
# 練習1
class Foo: def f1(self): print('Foo.f1') def f2(self): # print('Foo.f2') self.f1() class Bar(Foo): def f1(self): print('Bar.f1') obj = Bar() # {} obj.f2()
# 練習2 class Foo: def __f1(self): # _Foo__f1() print('Foo.f1') def f2(self): # print('Foo.f2') self.__f1() # _Foo__f1() class Bar(Foo): def __f1(self): # # _Bar__f1() print('Bar.f1') obj = Bar() # {} obj.f2()
多繼承
繼承多個父類的被稱為多繼承
多繼承下的屬性查詢
多繼承下的屬性查詢一般分為按照廣度查詢和按照深度查詢
新式類都是按照廣度查詢的
class G: def test(self): print('from A') class E(G): def test(self): print('from B') pass class F(G): def test(self): print('from C') pass class B(E): def test(self): print('from D') pass class C(F): def test(self): print('from B') pass
class D(G): def test(self): print('from B') pass
class A(B,C,D): def test(self): print('from A') pass print(F.mro()) # 查詢順序 [<class '__main__.B'>, <class '__main__.E'>, <class '__main__.C'>, <class '__main__.F'>, <class '__main__.D'>, <class '__main__.G'>, <class 'object'>] f1 = F() f1.test()
經典類都是按照深度查詢順序查詢的
class G: def test(self): print('from A') class E(G): def test(self): print('from B') pass class F(G): def test(self): print('from C') pass class B(E): def test(self): print('from D') pass class C(F): def test(self): print('from B') pass
class D(G): def test(self): print('from B') pass
class A(B,C,D): def test(self): print('from A') pass print(F.mro()) # 查詢順序 [<class '__main__.B'>, <class '__main__.E'>, <class '__main__.G'>, <class '__main__.C'>, <class '__main__.F'>, <class '__main__.D'>, <class 'object'>] f1 = F() f1.test()
二、super()和mro列表的使用
super()應用
super()會返回一個特殊的物件,該物件會參考發起屬性查詢的那一個類的mro列表,依次去當前類的父類中查詢屬性。
mor列表
mro()會顯示類的繼承順序,mor列表會按照從左到右開始查詢父類,直到找到第一個匹配這個屬性的類為止,類.mro()檢視mro列表
class B: def test(self): print('B---->test') def aaa(self): print('B---->aaa') class A: def test(self): print('A---->test') super().test() class C(A, B): def aaa(self): print('C----->aaa') c = C() c.test() # 列印結果: A---->test B---->test print(C.mro())
三、多型與多型性
什麼是多型
多型指的是一類事物有多種形態,(一個抽象類有多個子類,因而多型的概念依賴於繼承)
例如動物的多種形態:人、狗、豬
# 多型:同一種事物的多種形態,動物分為人類,豬類(在定義角度) # 方式1 class Animal: def run(self): raise Excecption('子類必須實現這個方法') class People(Animal): def run(self): print('人正在走') class Pig(Animal): def run(self): print('pig is walking') class Dog(Animal): def run(self): print('dog is running') peo = People() pig = Pig() d = Dog() peo.run() pig.run() d.run()
# 方式2 import abc class Animal(metaclass=abc.ABCMeta): # 同一類事物:動物 @abc.abstractmethod def talk(self): pass class People(Animal): # 動物的形態之一:人 def talk(self): print('say hello') class Dog(Animal): # 動物的形態之二:狗 def talk(self): print('say wangwang') class Pig(Animal): # 動物的形態之三:豬 def talk(self): print('say aoao')
什麼是多型性
多型性是指具有不同功能的函式可以使用相同的函式名,這樣就可以用一個函式名呼叫不同內容的函式。在面向物件方法中一般是這樣表述多型性:向不同的物件傳送同一條訊息,不同的物件在接收 時會產生不同的行為(即方法)。也就是說,每個物件可以用自己的方式去響應共同的訊息。所謂訊息,就是呼叫函式,不同的行為就是指不同的實現,即執行不同的函式。
#多型性:一種呼叫方式,不同的執行效果(多型性) def func(obj): obj.run() func(peo1) func(pig1) func(d1) # peo1.run() # pig1.run() # 多型性依賴於:繼承 ##多型性:定義統一的介面, def func(obj): #obj這個引數沒有型別限制,可以傳入不同型別的值 obj.run() #呼叫的邏輯都一樣,執行的結果卻不一樣 func(peo1) func(pig1) func(d1)
總結
多型:同一種事物的多種形態,動物分為人類,豬類(在定義角度)多型性:一種呼叫方式,不同的執行效果(多型性)
三、為什麼要用多型性(多型性的好處)
(1)增加了程式的靈活性
以不變應萬變,不論物件千變萬化,使用者都是同一種形式去呼叫,如func(animal)
(2)增加了程式額可擴充套件性
通過繼承animal類建立了一個新的類,使用者無需更改自己的程式碼,還是用func(animal)去呼叫