多重繼承

      在〈多重繼承〉中尚無留言

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()
結果 : 
空中生物
水中生物
陸地生物
用飛的
用游的
用跑的

發佈留言

發佈留言必須填寫的電子郵件地址不會公開。 必填欄位標示為 *