2020年9月17日星期四

[課後作業] 第047講:魔法方法:定制序列|課後測試題及答案

[課後作業] 第047講:魔法方法:定制序列|課後測試題及答案




《零基礎入門學習Python》視頻下載地址:傳送門
fz&r[bQ9ZG;6O?yhT1qV"~X:}A+
測試題(筆試,不能上機哦~):`bFC?Ot-
Y8@ rZu^:iIK'Cjw43]D90RovL1O
0.你知道Python基於序列的三大容器類指的是什麼嗎?Mt=krnwJ!+

5Su<hs1c:Y&DGA>nzN`@Lk=rq"O
1. Python允許我們自己定制容器,如果你想要定制一個不可變的容器(像String),你就不能定義什麼方法?~C=n5p
`WR:S*2l4ToawQ!5iV$kh?
}ag5u{@7P:J[G]oU2p!.Q^;
2.如果希望定制的容器支持reversed()內置函數,那麼你應該定義什麼方法?k,N3X{
DR[ra}b<e'fl3K _*yF@CWdo
o#z>PV:v7"[RCG8Tgih~|bL3UF@-D
3.既然是容器,必然要提供能夠查詢“容量”的方法,那麼請問需要定義什麼方法呢?-e<l$53#p
'0N:u;{VcH 2"7QE.r]l=R~L
Jax*l%,wAC;c#tO4@Tu]​​hZ"pF (j!sV
4.通過定義哪些方法使得容器支持讀、寫和刪除的操作?}:
8J=HpQ7x`U2{),]Fu9G 6IZR
U"@'=S1$j)>V6+,(9<i*Y
5.為什麼小甲魚說“在Python中的協議就顯得不那麼正式”?'sw [3Z

(HSMQ+mP>6;`b:X?*CI3LAEu

HKuD+aWS#94t'zXo,e=(3
動動手(一定要自己動手試試哦~):RC?}eB#
+krh&Z*" `Ab1pXQ({i_N
0.根據課堂上的例子,定制一個列表,同樣要求記錄列表中每個元素被訪問的次數。這一次我們希望定制的列表功能更加全面一些,比如支持append()、pop( )、extend()原生列表所擁有的方法。你應該如何修改呢?5sf ze
kCTEcd[q|)S:lIzug?sLf3XZ
要求1:實現獲取、設置和刪除一個元素的行為(刪除一個元素的時候對應的計數器也會被刪除)%}-80kF
要求2:增加counter(index)方法,返回index參數所指定的元素記錄的訪問次數H:)P!6]wl2
要求3:實現append()、pop( )、remove()、insert()、clear()和reverse()方法(重寫這些方法的時候注意考慮計數器的對應改變)7_y0w
[{()HB,hIV_Y:&
Gu6wP7KT]b 今天只有一道動動手的題目,但在寫代碼的時候要時刻考慮到你的列表增加了計數器功能,所以請務必要考慮周全再提交答案。ESp,J_
k!5ajh_VA"vr=+LiQpUe&
附課堂上的例子:鐗堟潈灞炰簬錛 bbs.fishc.com
wp*+n9)|QBg.iLZYCF&WK'

  1. class CountList:
  2.         def __init__(self, *args):
  3.                 self.values = [x for x in args]
  4.                 self.count = {}.fromkeys(range(len(self.values)), 0)

  5.         def __len__(self):
  6.                 return len(self.values)

  7.         def __getitem__(self, key):
  8.                 self.count[key] += 1
  9.                 return self.values[key]
複製代碼

3.請寫下這一節課你學習到的內容:格式不限,回憶並複述是加強記憶的好方式!~:|Acn@rX=Lxu%26zQWp`jKY

請務必自己先動手,貪一時之快先看答案,您將失去一次鍛煉的機會。<M$.SZPf
ldLShGu3f9Dz7bgOMBIt+Rni#wyXoW
回复您的答案即可查看參考答案!
ISQ?.Xp~@}
6j];0i5#u?}{p:d<oR 3z%|xnC
csr:w3KE-^)dmQ1aZCkNGLq
測試題答案:

本帖隱藏的內容

鐗堟潈灞炰簬锛�bbs.fishc.com
0. 你知道 Python 基于序列的三大容器类指的是什么吗?$ziXO
7a"f^w[o&40x$TZ}]6-I ?l9Q
答:无疑是列表(List),元组(Tuple)和字符串(String)啦。Gnh)T<UL}
|>0Mq!A8$vE7-W):2Sj_<6
0+_)z*={eqEn;]t>J8XL
1. Python 允许我们自己定制容器,如果你想要定制一个不可变的容器(像 String),你就不能定义什么方法?p*m(6RzE
4:XvMOsD[jf3?R>Wn297@5{iA^CP,
答:如果你想要定制一个不可变的容器(像 String),你就不能定义像 __setitem__() 和 __delitem__() 这些会修改容器中的数据的方法。hqA|M^
e]_DF|r+V94pq,b12;hyLU*
o.LbiCE%O@98sg{f3_[0Ij
2. 如果希望定制的容器支持 reversed() 内置函数,那么你应该定义什么方法?6"B41
5Zsk198o:NgLluD(h) Bt`fnVG
答:应该定义 __reversed__() 方法,提供对内置函数 reversed() 的支持。AZ,v~1:yc
Ci47LTyXA;ckou9m'lJMnq,DS
4.*GF$]JC)8cV=ySzTuHQ-f<{[>}h3
3. 既然是容器,必然要提供能够查询“容量”的方法,那么请问需要定义什么方法呢?iEw"+yr0J
SUitM8JagQ"cGL;R_(H*msN6
答:在 Python 中,我们通过 len() 内置函数来查询容器的“容量”,所以容器应该定义 __len__() 方法。L_)s-
-@<P]T^3Bsg;LNql[1JQ5?{

4. 通过定义哪些方法使得容器支持读、写和删除的操作?2uA#mNR{&t
azLQ9i?3~m@k(-+^r;$:u
答:读 —— __getitem__(),写 —— __setitem__(),删除 —— __delitem__(),"u8yeo
S_>]X5uZW.2$8Q1LFxgqN@nHrE,OcJ
Nm7D5*_&EJhGra34)Mtz
5. 为什么小甲鱼说“在 Python 中的协议就显得不那么正式”?PXY]
j,pDyaP3N_erm4v-XG+hO29Q(!]Zo'
答:在 Python 中,协议更像是一种指南。这有点像我们之前在课后作业中提到的“鸭子类型”(忘了的朋友请戳:http://bbs.fishc.com/thread-51471-1-1.html) —— 当看到一只鸟走起来像鸭子、游泳起来像鸭子、叫起来也像鸭子,那么这只鸟就可以被称为鸭子。Python就是这样,并不会严格地要求你一定要怎样去做,而是让你靠着自觉和经验把事情做好!)]K|kS

鏉ヨ嚜锛�bbs.fishc.com
Izqlb87J~$ft01Y-n!@wx69MD,PF.
%lV@(W6,7zFha"ki^'O<#SIZp
动动手答案:

本帖隐藏的内容

鐗堟潈灞炰簬錛 bbs.fishc.com
0.根據課堂上的例子,定制一個列表,同樣要求記錄列表中每個元素被訪問的次數。這一次我們希望定制的列表功能更加全面一些,比如支持append()、pop()、extend()原生列表所擁有的方法。你應該如何修改呢?3w|Yp
KA:JI1`q.E9oCW @Pk2Z|p&N
要求1:實現獲取、設置和刪除一個元素的行為(刪除一個元素的時候對應的計數器也會被刪除)@M>X{^
要求2:增加counter(index)方法,返回index參數所指定的元素記錄的訪問次數C]A}*
要求3:實現append()、pop()、remove()、insert()、clear()和reverse()方法(重寫這些方法的時候注意考慮計數器的對應改變).$vsV}MEz^
($;!.MI8ga^vCJ*Xe1&lj
"9:L!E8Im}CJ4O^&?j_Zwe;D
答案:為了實現這麼多功能,我們不能再用字典來存放元素的計數了。因為對於列表來說,如果你刪除其中一個元素,那麼其他元素的下標都會發生相應的變化(利用下標作為鍵的字典肯定就不能應對自如)。因此,我們改用一個列表來存放對應的元素的計數。Fo0B{>ju
WXSN5bY%v82u`k1G.T{]R=#xh_|
下邊的CountList類繼承並嚴重依賴其父類(list )的行為,並按要求重寫了一些方法。L$%0c]"w>b
W(y'2"bZL-;f8^ngkc|&s
代碼清單:鏉ヨ嚜錛 bbs.fishc.com
{SWj_[C|sOA]yND!UG:
  1. class CountList(list):
  2.     def __init__(self, *args):
  3.         super().__init__(args)
  4.         self.count = []
  5.         for i in args:
  6.             self.count.append(0)

  7.     def __len__(self):
  8.         return len(self.count)

  9.     def __getitem__(self, key):
  10.         self.count[key] += 1
  11.         return super().__getitem__(key)

  12.     def __setitem__(self, key, value):
  13.         self.count[key] += 1
  14.         super().__setitem__(key, value)

  15.     def __delitem__(self, key):
  16.         del self.count[key]
  17.         super().__delitem__(key)

  18.     def counter(self, key):
  19.         return self.count[key]

  20.     def append(self, value):
  21.         self.count.append(0)
  22.         super().append(value)

  23.     def pop(self, key=-1):
  24.         del self.count[key]
  25.         return super().pop(key)

  26.     def remove(self, value):
  27.         key = super().index(value)
  28.         del self.count[key]
  29.         super().remove(value)

  30.     def insert(self, key, value):
  31.         self.count.insert(key, 0)
  32.         super().insert(key, value)

  33.     def clear(self):
  34.         self.count.clear()
  35.         super().clear()

  36.     def reverse(self):
  37.         self.count.reverse()
  38.         super().reverse()
複製代碼

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

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

常言道:“無規矩不成方圓”,講的是萬事萬物的發展都要在一定的規則下去運行,只有遵循一定的協議去做,事情才能夠按照正確的道路去發展。我們今天要談的是定制容器,想要成功的實現容器的定制,我們要先談一談協議,那麼什麼是協議呢?
(1)協議是什麼?
協議(Protlcols)與其他編程語言中的接口很相似,它規定你在哪些地方必須定義哪些東西。然而,在Python中的協議就顯得不那麼正式了。事實上,Python中的協議更像是一種指南,一種建議。
例如,我們之前談到的鴨子類型(DuckTyping):當看到一隻鳥走起來像鴨子、游泳起來像鴨子、叫起來也像鴨子,那麼這隻鳥就可以被稱為鴨子。
Python就是這樣,它並不會嚴格要求你要怎樣去做,而是靠你自覺和經驗去把事情做得更好。
(2)定制容器
在Python中,序列類型(例如:列表,元組,字符串)或者映射類型(例如:字典)都是屬於容器類型,它們都是裡面存放各式各樣的對象。那麼這一節課我們就來談定制容器。
我們需要知道的是有關定義容器的協議這裡有兩種區分:
如果說你希望定制的容器是不可變的話(例如元組、字符串),你只需要定義 __len__() 和__getitem__() 方法。
如果說你希望定制的容器是可變的話,那麼除了 需要定義 __len__() 和__getitem__() 方法之外,你還需要定義 __setitem__() 和 __delitem__() 兩個方法。
有關Python魔法方法的講解如果忘了的,可以看一下-> Python魔法方法詳解
(3)練習
編寫一個不可改變的自定義列表,要求記錄列表中每個元素被訪問的次數。
參數是可變數量的(*args),因為我們不知道用戶要傳入多少個數據,我們把用戶輸入的數據初始化為一個列表,self.values 就是一個列表,我們通過列表推導式的形式把數據存放到self.values 這個列表中。另外,還需要記錄列表中每個元素被訪問的次數,我們立刻會想到字典,我們把每個元素在列表中的下標作為字典的鍵,然後值就是累計的訪問次數。我們定義 self.count 這個字典,初始化可以使用fromkeys ,並把所有下標對應的Key所對應的值初始化為0。我們這是一個不可變的容器,所以需要定義__len__() 和__getitem__() 方法, __len__() 就直接是返回len(self.values) 的值,__getitem__() 中的key 就是對應的下標,我們這裡是獲取key對應的值,所以需要返回self.values[key],另外,對應著訪問了它一次,所以對應的self.count[key] 加1。
  1. class CountList:
  2. def __init__(self, *args):
  3. self.values = [x for x in args]
  4. self.count = {}.fromkeys(range(len(self.values)), 0)
  5. def __len__(self):
  6. return len(self.values)
  7. def __getitem__(self, key):
  8. self.count[key] += 1
  9. return self.values[key]
驗證運行:
  1. >>> c1 = CountList(1, 3, 5, 7, 9)
  2. >>> c2 = CountList(2, 4, 6, 8, 10)
  3. >>> c1.count
  4. {0: 0, 1: 0, 2: 0, 3: 0, 4: 0}
  5. >>> c2.count
  6. {0: 0, 1: 0, 2: 0, 3: 0, 4: 0}
  7. >>> c1[1]
  8. 3
  9. >>> c1.count
  10. {0: 0, 1: 1, 2: 0, 3: 0, 4: 0}
  11. >>> c1[2] + c2[2]
  12. 11
  13. >>> c1.count
  14. {0: 0, 1: 1, 2: 1, 3: 0, 4: 0}
  15. >>> c2.count
  16. {0: 0, 1: 0, 2: 1, 3: 0, 4: 0}

0 留言:

發佈留言