小甲魚Python第038講:類和物件:繼承 | 課後測試題及參考答案
測試題:
0.繼承機制給程式設計師帶來的最明顯的好處是?
可以有效的減少程式碼量。如果一個類A繼承自另一個類B,就把A叫做B的子類,把B稱作A的父類。A會擁有擁有的全部屬性和方法,不需要對於A再進行相似編輯。然而在子類程式設計的過程中,也可以重新定義某些定義,並重寫某些方法,(覆蓋原來父類所擁有的的屬性和方法,使得子類與父類擁有不同的功能。)在子類中追加新的屬性和方法是一種常用的操作。
1.如果按一下方式重寫魔法方法__init__結果會怎樣?
1 class MyClass: 2 def __init__(self): 3 return "I love fish !"
會報錯!因為__init__特殊方法不應當返回除了None以外的任何物件。
可以實現如下操作:
1 方法一: 2 class Myclass: 3 def __init__(self): 4 print("hello") 5 方法二: 6 class Myclass: 7 def __init__(self): 8 return 9 方法三:(會報錯) 10 class Myclass: 11 def __init__(self): 12 return 8938
錯誤如下:
1 Traceback (most recent call last):2 File "<pyshell#22>", line 1, in <module> 3 my = Myclass1() 4 TypeError: __init__() should return None, not 'int', not 'str'
2.當子類定義了與相同名字的屬性方法時,Python是否會自動刪除父類的相關屬性或方法?
不會。只是子類中重新定義的屬性方法在子類中會覆蓋與之相同的父類的屬性方法,在子類中此屬性方法會有另一種表現。但父類還有此屬性方法,只是子類“看不到”。
3.假設已經有鳥類的定義,現在我要定義企鵝類繼承於鳥類,但我們都知道企鵝是不會飛的,我們該如何遮蔽父類(鳥類)中飛的方法?
覆蓋父類方法,例如將函式體內容寫pass,這樣呼叫fly方法就沒有任何顯示l了。
1 class Bird: 2 def fly(self): 3 print("i can fly") 4 class Penguin(Bird): 5 def fly(self): 6 print("i can not fly") 7 # 或者 pass 8 9 bird = Bird() 10 penguin = Penguin() 11 bird.fly() 12 penguin.fly()
4.super函式有什麼“超級的地方”?
super函式超級的地方在於:你不需要明確給出任何基類的名字,他會自動幫您找出所有的基類以及對應的方法。由於你不用給出基類的名字,這就意味著你如果需要改變了類繼承關係,你只要改變class語句裡的父類即可,而不必在大量的程式碼中去修改所有被繼承的方法。
5.多重繼承使用不當會導致重複呼叫的問題,請分析一下程式碼在實際程式設計中有可能導致什麼問題?
1 class A(): 2 def __init__(self): 3 print("進入A") 4 print("離開A") 5 class B(A): 6 def __init__(self): 7 print("進入B") 8 A.__init__(self) 9 print("離開B") 10 class C(A): 11 def __init__(self): 12 print("進入C") 13 A.__init__(self) 14 print("離開C") 15 class D(B,C): 16 def __init__(self): 17 print("進入D") 18 B.__init__(self) 19 C.__init__(self) 20 print("離開D")
多重繼承容易造成重複呼叫的問題。在上面的程式碼中主要體現在D類的呼叫上。
關於危害,小甲魚是這樣說的:假設A中的初始化方法中有一個計數器,那這樣D一例項化,A的計數器就跑兩次(如果遇到多個鑽石結構還可能會耕讀,呼叫更復雜)。這樣會很明顯是不符合程式設計的初衷的。程式用該是可控的,而不能受到繼承關係影響)。
上面的程式碼在呼叫D時,結果輸出是這樣的:
1 >>> a = A() 2 in A 3 out A 4 >>> b = B() 5 in B 6 in A 7 out A 8 out B 9 >>> c = C() 10 in C 11 in A 12 out A 13 out C 14 >>> d = D() 15 in D 16 in B 17 in A 18 out A 19 out B 20 in C 21 in A 22 out A 23 out C 24 out D
6.如何解決上一題中出現的問題?
1 class A: 2 def __init__(self): 3 print("A1") 4 print("A2") 5 class B(A): 6 def __init__(self): 7 print("B1") 8 super().__init__() 9 print("B2") 10 class C(A): 11 def __init__(self): 12 print("C1") 13 print("C2") 14 class D(B,C): 15 def __init__(self): 16 print("D1") 17 super().__init__() 18 print("D2") 19 20 實現結果如下: 21 >>> d = D() 22 D1 23 B1 24 C1 25 C2 26 B2 27 D2 28 29 30 class A: 31 def __init__(self): 32 print("A1") 33 print("A2") 34 class B(A): 35 def __init__(self): 36 print("B1") 37 super().__init__() 38 print("B2") 39 class C(A): 40 def __init__(self): 41 print("C1") 42 super().__init__() 43 print("C2") 44 class D(B,C): 45 def __init__(self): 46 print("D1") 47 super().__init__() 48 print("D2") 49 50 實現結果如下: 51 >>> D = D() 52 D1 53 B1 54 C1 55 A1 56 A2 57 C2 58 B2 59 D2
關於super()的用法以及細節可以參考:
https://www.cnblogs.com/miyauchi-renge/p/10923127.html
動動手:
0.定義一個點(Point)類和直線(Line)類,使用getLen方法可以獲得直線的長度。
1 import math 2 class Point: 3 def __init__(self,x, y): 4 self.x = x 5 self.y = y 6 def getX(self): 7 return self.x 8 def getY(self): 9 return self.y 10 11 class Line: 12 def __init__(self,p1,p2): 13 self.x = p1.getX()-p2.getX() 14 self.y = p1.getY()-p2.getY() 15 self.len = math.sqrt(self.x*self.x+self.y*self.y) 16 def getLen(self): 17 return self.len
1.展示一個你的作品,你已經掌握了大部分Python的基礎知識,花一個星期做一個好的作品。(可以是遊戲、應用軟體、指令碼),使用上學過的任何東西(類,字典,函式,列表···)來改進你的程式。