1、繼承python
原則:大部分使用繼承的場合均可以用組合取代或者簡化,而多重繼承則須要不惜一切的避免。算法
1. 什麼是繼承ide
繼承:用於指明一個類的大部分或者所有功能都是從一個父類得到的。此時,父類的實例的全部動做可能都會工做在子類的實例上,這樣能夠把通用的功能放在父類裏邊,而後給子類設定一些特別的功能。函數
父類和子類的三種交互方式:ui
① 子類上的動做徹底等同於父類上的動做spa
② 子類上的動做徹底覆蓋了父類上的動做prototype
③ 子類上的動做部分替換了父類上的動做code
2. 隱式繼承對象
若是在父類中定義了一個函數,而在子類中沒有定義,則會發生隱式的繼承。也就是說,子類的實例能夠調用僅在父類中定義過而在子類中沒有定義過的函數。blog
1 class Parent(object): 2 3 def implicit(self): 4 print("PARENT IMPLICIT()") 5 6 class Child(Parent): 7 pass 8 9 dad = Parent() 10 son = Child() 11 12 dad.implicit() 13 son.implicit()
輸出爲
PARENT IMPLICIT()
PARENT IMPLICIT()
3. 顯式覆蓋
若是想要在子類裏的函數有不一樣的功能,則必須使用顯式覆蓋,這在子類中定義一個同名函數就能夠了,如
1 class Parent(object): 2 3 def override(self): 4 print("PARENT OVERRIDE()") 5 6 class Child(Parent): 7 8 def override(self): 9 print("CHILD OVERRIDE()") 10 11 dad = Parent() 12 son = Child() 13 14 dad.override() 15 son.override()
輸出爲
PARENT OVERRIDE()
CHILD OVERRIDE()
4. 在運行前或運行後替換
替換是覆蓋的一種特例。它容許咱們在父類定義的內容運行以前或以後再去修改子類的行爲。
其方法爲,首先像上例同樣覆蓋父類的函數,而後用super()調用該函數在父類裏的版本。
1 class Parent(object): 2 3 def altered(self): 4 print("PARENT altered()") 5 6 class Child(Parent): 7 8 def altered(self): 9 print("CHILD, BEFORE PARENT altered()") # 顯式覆蓋 10 super(Child,self).altered() # 用super(Child,self)調用父類的同名函數 11 print("CHILD, AFTER PARENT altered()") # 仍爲顯式覆蓋的部分 12 13 dad = Parent() 14 son = Child() 15 16 dad.altered() 17 son.altered()
輸出爲
PARENT altered()
CHILD, BEFORE PARENT altered()
PARENT altered()
CHILD, AFTER PARENT altered()
可見,一方面,咱們能夠顯式覆蓋,重寫子類同名函數的內容和功能;另外一方面,能夠用super(Child,self)函數在中間調用父類的同名函數,而它並不影響先後的覆蓋內容。
所以,咱們能夠在子類函數運行前或運行後替換,這取決於super()的位置。
5. 三種方式的組合使用
1 class Parent(object): 2 3 def implict(self): 4 print("PARENT implict()") 5 6 def override(self): 7 print("PARENT override()") 8 9 def altered(self): 10 print("PARENT altered()") 11 12 class Child(Parent): 13 14 def override(self): 15 print("CHILD override()") 16 17 def altered(self): 18 print("CHILD, BEFORE PARENT altered()") 19 super(Child, self).altered() 20 print("CHILD, AFTER PARENT altered()") 21 22 dad = Parent() 23 son = Child() 24 25 dad.implict() 26 son.implict() 27 28 dad.override() 29 son.override() 30 31 dad.altered() 32 son.altered()
輸出爲
PARENT implict()
PARENT implict()
PARENT override()
CHILD override()
PARENT altered()
CHILD, BEFORE PARENT altered()
PARENT altered()
CHILD, AFTER PARENT altered()
6. super()函數
① 多重繼承
指定義的類繼承了一個或多個類,例如
class SuperFun(Child, BadStuff): pass
此時,一旦在SuperFun的實例上調用任何隱式動做,Python就必須返回到Child和BadStuff的類層次結構中去查找可能的函數,並且必須用固定的順序去查找。
爲此,Python使用了「Method Resolution Oder(方法解析順序),MRO」+C3算法,並提供super()函數,用於實現這些功能。這樣,就能夠方便的使用super()來查詢各父類的函數了。
② super()與__init__的搭配使用
super()最多見的用法是,在父類的__init__函數中使用。它使得咱們能夠先在子類中實現一些功能,而後再讓父類初始化,例如
1 class Child(Parent): 2 3 def __init__(self, stuff): 4 self.stuff = stuff 5 super(Child, self).__init__()
2、組合
組合可以實現和繼承幾乎徹底相同的功能,但它採用的方法並不是是隱式繼承,而是經過調用模塊裏的函數來實現。
1 class Other(object): 2 3 def implicit(self): 4 print("OTHER implicit()") 5 6 def override(self): 7 print("OTHER override()") 8 9 def altered(self): 10 print("OTHER altered()") 11 12 class Child(object): 13 14 def __init__(self): 15 self.other = Other() 16 17 def implicit(self): 18 self.other.implicit() 19 20 def override(self): 21 print("CHILD override()") 22 23 def altered(self): 24 print("CHILD, BEFORE OTHER altered()") 25 self.other.altered() 26 print("CHILD, AFTER OTHER altered()") 27 28 son = Child() 29 30 son.implicit() 31 son.override() 32 son.altered()
輸出爲
OTHER implicit()
CHILD override()
CHILD, BEFORE OTHER altered()
OTHER altered()
CHILD, AFTER OTHER altered()
可見,這裏並非爲Child指定了一個父類,而是將父類的功能打包爲一個模塊(實質也是一個類),而後直接調用模塊裏面的函數,這也可以完成和繼承相同的功能。
3、繼承和組合的應用場合
繼承和組合事實上都是爲了解決代碼的複用問題。前者經過建立一種讓咱們在子類裏隱含父類的功能的機制來解決這個問題,後者經過模塊/類中的函數調用達到了相同的目的。關於兩者的選擇,大致上有3個指導原則:
1. 避免多重繼承。多重繼承複雜且不可靠,若是要使用,須要鑽研一下類層次結構及其前因後果。
2. 若是有一些代碼會在不一樣位置和場合應用到,就用組合將它們作成模塊。
3. 只有在代碼的可複用部分之間有清楚的關聯,能夠經過一個單獨的共性鏈接起來的時候,才使用繼承。
【鞏固練習】代碼風格參考 PEP 8 -- Style Guide for Python Code
【注意】在有的語言如JavaScript中,對象實際上是類的副本,這樣的語言叫原型(prototype)語言,這種語言中類和對象除了用法之外沒多少不一樣。但在Python中,類則比較像是用來建立對象的模板。