繼承(Inherit)
物件導向理論中, 最有用的就是繼承的機制. 比如要設計Pikachu, Eve, Frog三個神奇寶貝. 最快速的方法就是把這三個種類相同處, 設定在父類別Pokemon中, 然後此三種再繼承Pokemon. 此時我們稱Pokemon為父類別, 而Pikachu, Eva, Frog則稱為子類別. 子類別繼承父類別後, 就擁有父類別所有的物件方法, 如setLevel(), getLevel(), 所以子類別就不需要再重新寫一次
class Pokemon(object): def __init__(self, level): self.level=level def setSpeed(self, s): self.speed=s class Pikachu(Pokemon): pass class Eve(Pokemon): pass p1=Pikachu(10) p1.setSpeed(100) print(f'p1 level: {p1.level}') print(f'p1 speed : {p1.speed}') 結果 p1 level: 10 p1 speed : 100
物件變數繼承
物件變數必需觸發物件方法或建構子才會生成,所以物件變數沒有繼不繼承的問題。
子類別方法擴充
子類別也可以自行擴充其功能
class Pikachu(Pokemon): def lighting(self): print("一萬伏閃電攻擊")
方法覆蓋(Override)
子類別定義方法時,若名稱與父類別相同,則稱為覆蓋。父類別方法被子類別覆蓋後就屍骨無存。此時若在子類別方法中要調用父類別方法,那該怎麼辦呢? 只此時只好使用觀落音法了,super() 就是廟裏負責觀落音的廟公廟婆,如下代碼中,使用super().getLevel()
在super的參數中, Python 3.0直接空白即可, 若是Python2.0, 則需寫為
super(Pikachu, self).setLevel(level);
其實super()裏的參數, 是為了多重繼承時的設定. 到目前為止, 我們都只講到單一繼承
class Pikachu(Pokemon):
def lighting(self):
print("一萬伏閃電攻擊")
def getLevel(self):
print("皮卡丘 Level %d" % super().getLevel())
建構子覆蓋
子類別繼承了父類別後,若子類別沒有建構子,則會繼承父類別建構子。但子類別若有建構子,則會覆蓋父類別建構子。
依物件導向理論,Java及C#都會自動加預設建構子,並且於建構子第一行自動加入super()。 但在Python中,並不會自動加super()。所以建議在Python中,每個類別都要寫建構子,並且於子類別建構子的第一行手動加入 super().__init__(),這樣才能調用父類別建構子。
class Pokemon(object):
def __init__(self, level=0, w=0):
self.level=level
print("Pokemon 出生了 : %d" % self.level)
class Pikachu(Pokemon):
def __init__(self, level=0):
super().__init__(level)
print("Pikachu 出生了")
p1=Pikachu(20)
結果 :
Pokemon 出生了 : 20
Pikachu 出生了
多型(Polymorphism)
在上面的例子中, p1到底是Pokemon, 還是Pikachu, 此時我們也混亂了. 所以有一個函數可以解析此變數的型態, 就是isinstance().
if isinstance(p1, Pokemon): print("Pokemon") else: print("Pikachu")
接下來, 再試試下面的代碼
p2=Pikachu() if isinstance(p2, Pokemon): print("p2 是 神奇寶貝") if isinstance(p2, Pikachu): print("p2 是 皮卡丘") 結果 : p2 是 神奇寶貝 p2 是 皮卡丘
妖壽喔, 怎麼p2是神奇寶貝, 也是皮卡丘呢. 這個叫廢話, 皮卡丘就是神奇寶貝啊, 這就是多型的意思. 不過, 神奇寶貝不一定是皮卡丘喔.