2020年9月16日星期三

[課後作業] 第039講:類和對象:拾遺|課後測試題及答案

[課後作業] 第039講:類和對象:拾遺|課後測試題及答案 




《零基礎入門學習Python》視頻下載地址:傳送門|CsLOn5w
zhm4@-[ef"]>B(<1$FLw!NkXy
測試題:來自:bbs.fishc.com
_6S`Fm;TDY39}Mswb-ZP )=E
0.什麼是組合(組成)?來自:bbs.fishc.com
Az<pKkwv&-'q[,36)LZ!MClxuIQ:H
Z1(!$S,Qy_ozNw06*>.GFT?&:Js< h5
1.什麼時候用組合,什麼時候用繼承?版權屬於:bbs.fishc.com
}j4xC#Lnm!l?+pA%*'1io
JtOv;pFKZ!r9nkQ"y7,6.{jsPg4
2.類對象是在什麼時候產生?版權屬於:bbs.fishc.com
>o,#LR(7|WsJ[t;bG3x~Yd6m]_2U@
y`5R0T^bZoht}OcWFz+qd[I?uHv|
3.如果對象的屬性跟方法名字相同,會怎樣?wj!:l
RkTL?uIS}-mtWN~r+5;B|i"c.wjq>Y
]"C&HlUFj }Y;6Wyn1!of_KT~9`M='
4 .請問以下類定義中哪些是類屬性,哪些是實例屬性?yOYU|;


  1. class C:
  2.         num = 0
  3.         def __init__(self):
  4.                 self.x = 4
  5.                 self.y = 5
  6.                 C.count = 6
複製代碼

-C(rtMl%"06Jg8YLm9_#yd
5.請問以下代碼中,bb對象為什麼調用printBB()方法失敗?0VBg*|
  1. class BB:
  2.         def printBB():
  3.                 print("no zuo no die")

  4. >>> bb = BB()
  5. >>> bb.printBB()
  6. Traceback (most recent call last):
  7.   File "<pyshell#8>", line 1, in <module>
  8.     bb.printBB()
  9. TypeError: printBB() takes 0 positional arguments but 1 was given
複製代碼

#Mes6I95B7+z0~G{=Qf3V-%'
動動手:
A5*S>jNn]"PV tUYK7eB26?4
0.思考這一講我學習的內容,請動手在一個類中定義一個變量,用於跟踪該類有多少個實例被創建(當實例化一個對象,這個變量+1,當銷毀一個對象,這個變量自動-1)。fY.|5m
(is38D9y:LQ=6B! )Oz&vc {|u
$Jwq4|9CB%5G=e@yY`UZ
1.定義一個棧(Stack)類,用於模擬一種具有後進先出(LIFO)特性的數據結構。至少需要有以下方法:
kYE>MD`L
:Cy{rD`!zd5}R^.AF*Vk@x
c-d6#fo;BJ+_awTPEj[e

方法名含義
isEmpty()判斷當前棧是否為空(返回True 或False)
push()往棧的頂部壓入一個數據項
pop()從棧頂彈出一個數據項(並在棧中刪除)
top()顯示當前棧頂的一個數據項
bottom()顯示當前棧底的一個數據項

D=O,kn8WmtH7}#0bapMre
3.請寫下這一節課你學習到的內容:格式不限,回憶並複述是加強記憶的好方式!qnw&xcWjhFk~[!{3VigyN=:#



回复您的答案即可查看參考答案!&b1aMg,Ff
fW,l@M~an#9)2v$O<7H:^Pogr
wN^O:F8UCMou3fB4[<!_2}S;jL&qei
測試題答案:

本帖隱藏的內容

版權屬於:bbs.fishc.com
0.什麼是組合(組成)?3HV.el Rr#
}t!Q:b0O{2-shFv[WKYM<$*r+IA|oV
答:Python繼承機制很有用,但容易把代碼複雜化以及依賴隱含繼承。因此,經常的時候,我們可以使用組合來代替。在Python裡組合其實很簡單,直接在類定義中把需要的類放進去實例化就可以了。!RPp9u%s
R@u8?ne-"ci*b_,>D4GpTPIZK^zg$
例子:Powered by bbs.fishc.com
  1. // 烏龜類
  2. class Turtle:
  3.     def __init__(self, x):
  4.         self.num = x
  5. // 魚類
  6. class Fish:
  7.     def __init__(self, x):
  8.         self.num = x
  9. // 水池類
  10. class Pool:
  11.     def __init__(self, x, y):
  12.         self.turtle = Turtle(x) // 組合烏龜類進來
  13.         self.fish = Fish(y) // 組合魚類進來
  14.      
  15.     def print_num(self):
  16.         print("水池裡總共有烏龜%d 只,小魚%d 條!" % (self.turtle.num, self.fish.num))

  17. >>> pool = Pool(1, 10)
  18. >>> pool.print_num()
複製代碼

5Y*gj[L(OGtdlpq`N+'xKM?U$6
1.什麼時候用組合,什麼時候用繼承?>&:}dW)
@nwv[Df!Ep)%rT^4hX1b '
答:根據實際應用場景確定。簡單的說,組合用於“有一個”的場景中,繼承用於“是一個”的場景中。例如,水池裡有一個烏龜,天上有一個鳥,地上有一個小甲魚,這些適合使用組合。青瓜是瓜,女人是人,鯊魚是魚,這些就應該使用繼承啦。A:fGkR6MD
>yYaKe+D}%{Pxhb-g_TsBkJ)GLvm
6+GKianO?4(b{^R#x9|Wr%vE
2.類對像是在什麼時候產生?WpEbi
GBz!0}OgC>,[ IV J~Zs:eiSunKp<1T
答:當你這個類定義完的時候,類定義就變成類對象,可以直接通過“類名.屬性”或者“類名.方法名()”引用或使用相關的屬性或方法。cR2Dt9As
g!tWn*z0|G $L6hR,X5QF"su_}2:
9WM}!TnfhS(vGl)Dz,"A#cmrHyY+X
3.如果對象的屬性跟方法名字相同,會怎樣?QmOX@f%8
Qz_HP%M#n:-SJjs$~4Tw}7YF
答:如果對象的屬性跟方法名相同,屬性會覆蓋方法。,r`(2yhK
SM|Hiu>Q`&sP}Rt% -WoY
  1. class C:
  2.         def x(self):
  3.                 print('Xman')

  4. >>> c = C()
  5. >>> cx()
  6. Xman
  7. >>> cx = 1
  8. >>> cx
  9. 1
  10. >>> cx()
  11. Traceback (most recent call last):
  12.   File "<pyshell#20>", line 1, in <module>
  13.     cx()
  14. TypeError: 'int' object is not callable
複製代碼

mej+t<}lY#]|;_6.S)=Rb
4.請問以下類定義中哪些是類屬性,哪些是實例屬性?n8TkM9
  1. class C:
  2.         num = 0
  3.         def __init__(self):
  4.                 self.x = 4
  5.                 self.y = 5
  6.                 C.count = 6
複製代碼

答:num和count是類屬性(靜態變量),x和y是實例屬性。大多數情況下,你應該考慮使用實例屬性,而不是類屬性(類屬性通常僅用來跟踪與類相關的值)。XGu^>"{?1
?Wb#J)Qpv=gk0DS;^F1mo+Tyu,
Pgsc<SQynx&0>8[bX~WY-]eJlvEG
5.請問以下代碼中,bb對象為什麼調用printBB()方法失敗?oGYDn3eIz
  1. class BB:
  2.         def printBB():
  3.                 print("no zuo no die")

  4. >>> bb = BB()
  5. >>> bb.printBB()
  6. Traceback (most recent call last):
  7.   File "<pyshell#8>", line 1, in <module>
  8.     bb.printBB()
  9. TypeError: printBB() takes 0 positional arguments but 1 was given
複製代碼

答:因為Python嚴格要求方法需要有實例才能被調用,這種限制其實就是Python所謂的綁定概念。所以Python會自動把bb對像作為第一個參數傳入,所以才會出現TypeError:“需要0個參數,但實際傳入了1個參數“。uELvK$mt
?!^{vbp=UIYRL}[x#:%qTF2PVSf-9
正確的做法應該是:來自:bbs.fishc.com
  1. class BB:
  2.         def printBB(self):
  3.                 print("no zuo no die")

  4. >>> bb = BB()
  5. >>> bb.printBB()
  6. no zuo no die
複製代碼

來自:bbs.fishc.com
P,ANt>(68ncgGF.^X3'jmr1&@CzK
動動手答案:

本帖隱藏的內容

版權屬於:bbs.fishc.com
0.思考這一講我學習的內容,請動手在一個類中定義一個變量,用於跟踪該類有多少個實例被創建(當實例化一個對象,這個變量+ 1,當銷毀一個對象,這個變量自動-1)。J}WC
!yp;mb)V>d+CJ@8<4`T-" 1glRjMB
代碼清單:Powered by bbs.fishc.com
  1. class C:
  2.         count = 0
  3.         
  4.         def __init__(self):
  5.                 C.count += 1

  6.         def __del__(self):
  7.                 C.count -= 1

  8. >>> a = C()
  9. >>> b = C()
  10. >>> c = C()
  11. >>> C.count
  12. 3
  13. >>> del a
  14. >>> C.count
  15. 2
  16. >>> del b, c
  17. >>> C.count
  18. 0
複製代碼

O{:HTM?tp8u.w2RLr1j`D}
1.定義一個棧(Stack)類,用於模擬一種具有後進先出(LIFO)特性的數據結構。至少需要有以下方法:$ZP5c.
q)k;v0$fOJtsZ2hKym1]C8z|%-L4r
方法名含義
isEmpty()判斷當前棧是否為空(返回True 或False)
push()往棧的頂部壓入一個數據項
pop()從棧頂彈出一個數據項(並在棧中刪除)
top()顯示當前棧頂的一個數據項
bottom()顯示當前棧底的一個數據項

代碼清單:來自:bbs.fishc.com
  1. class Stack:
  2.     def __init__(self, start=[]):
  3.         self.stack = []
  4.         for x in start:
  5.             self.push(x)

  6.     def isEmpty(self):
  7.         return not self.stack
  8.    
  9.     def push(self, obj):
  10.         self.stack.append(obj)

  11.     def pop(self):
  12.         if not self.stack:
  13.             print('警告:棧為空!')
  14.         else:
  15.             return self.stack.pop()

  16.     def top(self):
  17.         if not self.stack:
  18.             print('警告:棧為空!')
  19.         else:
  20.             return self.stack[-1]

  21.     def bottom(self):
  22.         if not self.stack:
  23.             print('警告:棧為空!')
  24.         else:
  25.             return self.stack[0]
複製代碼

2.請寫下這一節課你學習到的內容:格式不限,回憶並複述是加強記憶的好方式!

小甲魚希望你認真對待作業就像你希望小甲魚推出高質量視頻一樣渴望^_^

(一)組合
上節課我們學習了繼承和多繼承,但是我們有時候發現,有些情況你用繼承也不合適,用多繼承也不是,例如:現在現在要求定義一個類,叫水池,水池裡要有烏龜和魚。那大家就很苦惱了,用多繼承就顯得很奇葩了,因為如果把水池繼承烏龜和魚,那顯然就是不同物種。那怎樣才能把它們組成一個和諧的類呢,這就是我們今天首先要講的內容:組合。
組合的用法很簡單,舉例說明:
  1. class Turtle:
  2. def __init__(self, x):
  3. self.num = x
  4. class Fish:
  5. def __init__(self, x):
  6. self.num = x
  7. class Pool:
  8. def __init__(self, x, y):
  9. self.turtle = Turtle(x)
  10. self.fish = Fish(y)
  11. def print_num(self):
  12. print("水池里有乌龟 %d 只,小鱼 %d 条!" %(self.turtle.num, self.fish.num))
  13. >>> pool = Pool(1, 10)
  14. >>> pool.print_num()
  15. 水池里有乌龟 1 只,小鱼 10 条!
所謂的組合,就是把類的實例化放到新類裡面,那麼它就把舊類給組合進去了,不用使用繼承了,沒有什麼風險了。組合一般來說就是把幾個沒有繼承關係,沒有直線關係的幾個類放在一起,就是組合。要實現縱向關係之間的類,就使用繼承。
Python的特性還支持另外一種很流行的編程模式,叫做Mix-in,叫做混入的意思,有興趣的可以參見-> Python Mixin編程機制
(二)類、類對象和實例對象
我們一開始就說了,類、類對象和實例對像是三個不同的物種。先看代碼:
  1. >>> class C:
  2. count = 0
  3. >>> a = C()
  4. >>> b = C()
  5. >>> c = C()
  6. >>> a.count
  7. 0
  8. >>> b.count
  9. 0
  10. >>> c.count
  11. 0
  12. >>> c.count += 10
  13. >>> c.count
  14. 10
  15. >>> a.count
  16. 0
  17. >>> b.count
  18. 0
  19. >>> C.count
  20. 0
  21. >>> C.count += 100
  22. >>> C.count
  23. 100
  24. >>> a.count
  25. 100
  26. >>> b.count
  27. 100
  28. >>> c.count
  29. 10
我們這裡有一個C 類,只有一個屬性count ,初始化為0。實例化一個a,一個b,一個c,顯然a.count = 0,b.count = 0,c.count = 0。如果對c.count += 10,現在c.count = 10,但是 a.count = 0,b.count = 0。因為C 是一個類,在寫完C 之後就變成了一個類對象,因為Python無處不對象,所有的東西都是對象,方法也是對象,所以我們這裡C.count = 0 也是等於0 。此時我們對這個類對象加等於100 , C.count += 100,此時a.count = 100,b.count = 100,但是 c.count = 10。為什麼會這樣呢?
其實是因為c.count += 10 這裡c.count 被賦值的時候,我們是對實例化對象c 的屬性進行賦值,相當於我們生成了一個count 來覆蓋類對象的count,如圖:
類定義到類對象,還有實例對象a,b,c,需要注意的是,類中定義的屬性都是靜態屬性,就像C裡面的count,類屬性和類對像是相互綁定的,並不會依賴於下面的實例對象,所以當c.count += 10的時候,並不會影響到C,只是改變了c自身,因為在c.count += 10的時候,是實例對象c多了一個count的屬性,也就是實例屬性,它把類屬性給覆蓋了。這在以後還會繼續講解,在此之前,我們先談一下:如果屬性的名字和方法相同時,屬性會把方法覆蓋掉。舉例說明:
  1. >>> class C:
  2. def x(self):
  3. print("X-man")
  4. >>> c = C()
  5. >>> c.x()
  6. X-man
  7. >>> c.x = 1
  8. >>> c.x
  9. 1
  10. >>> c.x()
  11. Traceback (most recent call last):
  12. File "<pyshell#48>", line 1, in <module>
  13. c.x()
  14. TypeError: 'int' object is not callable
cx = 1 是實例化後的c ,創建了一個x 的屬性,這時如果要調用它的函數x() 就會報錯,出錯信息說:整型是不能被調用的。
這就是初學者容易發生的一個問題,如果屬性的名字和方法名相同,屬性會覆蓋方法。為了避免名字上的衝突,大家應該遵守一些約定俗成的規矩:
  • 不要試圖在一個類裡邊定義出所有能想到的特徵和方法,應該使用繼承和組合機制來進行擴展。
  • 用不同詞性命名,如屬性名用名詞,方法名用動詞。
(三)到底什麼是綁定?
Python 嚴格要求方法需要有實例才能被調用,這種限制其實就是Python 所謂的綁定概念。

0 留言:

發佈留言