Python/Java/C#的不同
Python的子類別,可以繼承多個父類別,稱為多重繼承。但 Java,C# 只能使用單一繼承。
public class FirstApp(){
public static void main(String args){
}
}
class Land{}
class Water{}
class Sky{}
class Frog extends Land{} <==只允許單一繼承Land
根本就沒有多重繼承
多重繼承,其實只是個幌子,因為壓根兒就沒有多重繼承這件事,這就算在C++也是一樣的。這就是為什麼Java/C#不使用多重繼承的原因。
class Frog(Land, Water, Sky):
pass
上面的 Frog 多重繼承了Land,Water 及 Sky 三個父類別。但三個父類別之間的關係如同父子一樣,也就是說 Frog 的父類別是 Land,而 Land 的父類別是 Water,最後 Water 的父類別是 Sky。
多重繼承有點像是斷決父子關係的情況,Land 跟 Water 明明是父子的特性,但卻對外宣稱互不認識。
if isinstance(Land, Water):
print("True")
else:
print("False")
結果 : False
多重繼承的目的
多重繼承的目的, 不外乎如下幾種
1. 承接所有父類別的功能
2. 多型
3. 群組分類
承接所有父類別的功能
在下面的代碼中, Frog 繼承了Pokemon, Land, Water 三個父類別, 所以Frog就具有
1. setLevel()
2. move()
3. breath()
三種功能.
class Pokemon(object): def __init__(self, l=0): self.level=l def setLevel(self, l): self.level=l class Land(object): def move(self): return "Jumping....." def breath(self): return "Lung....." class Water(object): def move(self): return "Swimming....." class Sky(object): def move(self): return "Flying....." class Frog(Pokemon, Land, Water): pass class Fish(Pokemon, Water): pass frog=Frog() print("Frog move : %s" % frog.move()) print("Frog breath : %s" % frog.breath()) fish=Fish() print("Fish move : %s" % fish.move())
父類別相同名稱屬性及方法
當多個父類別具有相同名稱的屬性及方法時,以最左邊的 Land 父類別優先繼承,因為最左邊是最下面的父類別,而 Water 及 Sky 的方法,都被 Land 的方法覆蓋掉。
以上例來說,Frog繼承了Pokemon,Land,及 Water。
Land及Water都具有相同的move()方法。 Land的move()方法是 Jumping, Water的 move()方法 是Swimming。
Frog繼承時,Land是寫在左邊,Water寫在右邊,所以是優先繼承了Land的move()。所以frog.move()就會執行Land的 move(),返回 “Jumping”。那有沒有可能使用 frog.move()去執行 Water 的 move() 並且返回 Swimming 呢? 答案是不行的,因為Water的 move() 被 Land 的 move() 覆蓋掉。
mro
mro 全名為 Method Resolution Order(方法解析順序),此函數記錄著繼承的順序。先看如下代碼的結果
import abc class Move(abc.ABC): @abc.abstractmethod def move(self): pass class Land(): def __init__(self): super().__init__() print("陸地生物") class Water(): def __init__(self): super().__init__() print("水中生物") class Sky(): def __init__(self): super().__init__() print("空中生物") class Frog(Land, Water, Sky): def __init__(self): super().__init__() f=Frog() print(Frog.mro()) 結果: 空中生物 水中生物 陸地生物 [<class '__main__.Frog'>, <class '__main__.Land'>, <class '__main__.Water'>, <class '__main__.Sky'>, <class 'object'>]
Frog的下一個為Land, 然後依序為Water, Sky, object
執行所有父類別的建構子
如下的Frog類別,繼承了 Land, Water, Sky 三個父類別,在 Frog 建構子中,如果要執行三個父類別的建構子,則每個父類別建構子第一行必需是 super().__init__(),然後Frog建構子也必需是 super().__init__(),如下藍色部份。
執行的順序,由右邊的父類別建構子開始,依序往左執行。
class Land(): def __init__(self): super().__init__() print("陸地生物") class Water(): def __init__(self): super().__init__() print("水中生物") class Sky(): def __init__(self): super().__init__() print("空中生物") class Frog(Land, Water, Sky): def __init__(self): super().__init__() f=Frog() 結果 : 空中生物 水中生物 陸地生物
上述的 super().__init__() 會執行所有父類別的建構子。其執行過程如下 :
1. 執行Frog的 __init__() ,其中的 super().__init__()是執行 Land的 __init__()
2. 在 Land的 __init()__又執行 super().__init__(),就是執行Water的 __init__()
3. 在Water的 __init__()又執行 super().__init__(),就是執行Sky的 __init__()
4. 在Sky的 __init__()又執行 super().__init__(),就是執行 object的 __init__()
5. 在 object的 __init__(),不執行任何東西,就直接返回。
6. 回到 Sky中,印出 “空中生物”
7. 回到 Water中,印出 “水中生物”
8. 回到 Land中,印出 “陸地生物”
以上的順序圖解如下
如果在Frog類別寫成 super(Land, self).__init__(),表示要執行Land的上一層類別建構子,也就是執行Water及Sky 的建構子。請注意,不包含Land的建構子。
那如果寫成 super(Sky, self).__init__(),則要執行Sky的上一層建構子,所以只有 object 的建構子會執行,結果是什麼都沒有。
執行所有父類別的一般方法
如果在子類別中,想執行所以父類別的一般方法,那麼就必需先設定一個抽象類別及抽象方法,然後將Land, Water, Sky三個類別繼承抽象類別,Frog再繼承三個父類別。
from abc import abstractmethod class Move(): @abstractmethod def move(self): pass class Land(Move): def __init__(self): super().__init__() print("陸地生物") def move(self): super().move() print("用跑的") class Water(Move): def __init__(self): super().__init__() print("水中生物") def move(self): super().move() print("用游的") class Sky(Move): def __init__(self): super().__init__() print("空中生物") def move(self): super().move() print("用飛的") class Frog(Land, Water, Sky): def __init__(self): super().__init__() def move(self): super().move() f=Frog() f.move() 結果 : 空中生物 水中生物 陸地生物 用飛的 用游的 用跑的