本周是培訓(xùn)的第三周,新知識點逐漸多了起來,程序的代碼量和復(fù)雜度遠(yuǎn)勝之前,不過也能明顯的感覺到個人邏輯思維的提升、代碼編寫愈發(fā)的熟練,本周涉及的知識點主要如下所示:
- 函數(shù)
名字(同變量命名)
參數(shù)、默認(rèn)值、可變參數(shù)(args, 組裝成元組)、關(guān)鍵字參數(shù)(kwargs,組裝成字典)、命名關(guān)鍵字參數(shù)(號后的參數(shù)在傳參的時候必須有參數(shù)名)
返回值(單個、多個亦可)
嵌套定義(與C、C++等高級編程語言不同,可以在一個函數(shù)里定義另一個函數(shù))
高階函數(shù) f(g(x))
lambda函數(shù)(匿名函數(shù))、【閉包、偏函數(shù)、柯里化】
decorator - 裝飾器 / 包裝器(通過裝飾器修飾函數(shù),讓函數(shù)在執(zhí)行過程中可以做更多額外的操作)
- 類和對象
面向?qū)ο笕筇匦裕悍庋b,繼承,多態(tài)
靜態(tài)方法與類方法(以判斷三角形三條邊設(shè)置是否合理為例)
- 靜態(tài)方法
@staticmethod
def is_valid(a, b, c):
return a + b > c and a + c > b and b + c > a - 類方法(消息依舊是發(fā)給類 可以用cls做更多的事)
@classmethod
def is_valid(cls, a, b, c):
print(cls)
print(type(cls))
return a + b > c and a + c > b and b + c > a
抽象類的定義
from abc import ABCMeta, abstractclassmethod
class GameObject(object, metaclass=ABCMeta):
def init(self, pos=(0,0), color=BLACK_COLOR):
self._pos = pos
self._color = color
@abstractclassmethod
def draw(self, screen): # 抽象方法,規(guī)范子類行為
pass
屬性訪問器與修改器(以奧特曼打小怪獸中的屬性hp為例)
- 屬性訪問器
@property
def hp(self):
return self._hp
-屬性修改器
@hp.setter
def hp(self, hp):
self._hp = hp if hp > 0 else 0
類與類、對象與對象之間的關(guān)系
- has-a --> 普通關(guān)聯(lián) - 聚合(強(qiáng)關(guān)聯(lián)) - 合成(不可分割)(從左到右由弱到強(qiáng))
- use-a --> 依賴關(guān)系
- is-a --> 繼承關(guān)系
程序設(shè)計原則
- 高內(nèi)聚:函數(shù)(類)只做一件事件(單一職責(zé)原則)
- 低耦合:代碼塊之間不能產(chǎn)生強(qiáng)關(guān)聯(lián)關(guān)系,不要和特定的運(yùn)行環(huán)境緊密耦合在一起
,迪米特法則(最少知識原則)
面向?qū)ο笤瓌t
- 單一職責(zé)原則(Single Responsibility Principle, SRP)
- 開閉原則(Open Close Principle, OCP)(對擴(kuò)展開放,對修改關(guān)閉)
- 依賴倒置原則(Dependence Inversion Principle, DIP)(模塊間的依賴通過抽象發(fā)生,實現(xiàn)類之間不發(fā)生直接的依賴關(guān)系,其依賴關(guān)系是通過接口或抽象類產(chǎn)生的)
- 里氏替換原則(Liskov Substitution Principle, LSP)(子類替換父類)
- 接口隔離原則(Interface Segregation Principles, ISP)(接口隔離原則的目的是系統(tǒng)解開耦合,從而容易重構(gòu)、更改和重新部署 客戶端不應(yīng)該依賴它不需要的接口)
- 合成聚合復(fù)用原則(能使用強(qiáng)關(guān)聯(lián)的地方就不要使用繼承)
- 迪米特法則(Law of Demeter, LOD)(最少知識原則)
- 異常機(jī)制
- 即處理程序在運(yùn)行過程中出現(xiàn)的意外狀況的手段,因為不是所有的問題都能夠在寫程序調(diào)試程序的時候就能發(fā)現(xiàn),代碼如下所示:
try:
# 把可能出狀況(在執(zhí)行時有風(fēng)險)的代碼放到try代碼塊保護(hù)起來
pass
except IOError:
# 如果try中出現(xiàn)了狀況就通過except來捕獲錯誤(異常)進(jìn)行對應(yīng)的處理
print("讀寫文件發(fā)生錯誤!")
except FileNotFoundError:
# except可以寫多個分別用于處理不同的異常狀況
pass
else:
# 如果沒有出狀況那么可以把無風(fēng)險的代碼放到else中執(zhí)行
pass
finally:
# 不管程序正常還是異常最后這里的代碼一定會實現(xiàn)
# 此處是最好的釋放外部資源的位置,因為這里的代碼總是會執(zhí)行
pass
- Json
- 即 javascript object notation (js對象表達(dá)式 有格式,半結(jié)構(gòu)化的純文本),用于傳輸字典、列表數(shù)據(jù)
json寫操作(字典-->字符串)
try:
with open("data.json","w",encoding="utf-8") as fs:
json.dump(mydict, fs) # mydict 為一字典
except IOError as e:
print(e)
json讀操作(字符串-->字典)
try:
with open("data.json","r",encoding="utf-8") as fs:
thy_dict = json.load(fs) # 讀字典
print(type(thy_dict))
print(thy_dict)
print(thy_dict["name"])
except IOError as e:
print(e)
print("處理結(jié)束!")
除了基礎(chǔ)知識的講解,本周側(cè)重運(yùn)用面向?qū)ο蟮乃枷雭斫鉀Q實際問題,筆者也在緊跟課堂講解進(jìn)度的同時,對練習(xí)項目中待解決的問題進(jìn)行了獨(dú)立思考,并給出了自己的實現(xiàn),下面就實現(xiàn)要點簡要的做一分享:
1. 21點
要點:
1)玩家先摸牌,計算機(jī)后摸牌(計算機(jī)分穩(wěn)健性(超過16分不再摸牌)和魯莽型(超過18分不再摸牌))
2)每次摸牌前提示是否摸牌,摸牌后自動記錄點數(shù)并顯示牌面
3)最終的結(jié)果分為:a. 玩家和計算機(jī)的點數(shù)和均超過21點,兩方均爆,平局
b. 玩家爆了,計算機(jī)未爆,計算機(jī)勝
c. 計算機(jī)爆了,玩家未爆,玩家勝
d. 計算機(jī)和玩家都未爆,且玩家的點數(shù)和大于計算機(jī),
玩家勝
e. 計算機(jī)和玩家都未爆,且玩家的點數(shù)和小于計算機(jī),
計算機(jī)勝
f. 計算機(jī)和玩家都未爆,且玩家的點數(shù)和等于計算機(jī),
平局
2. 五子棋
要點:
1)勝負(fù)裁決:以最后下的一顆棋子的坐標(biāo)為基準(zhǔn),通過判斷垂直,水平,主對角線,斜對角線四個方向來判斷輸贏,每個方向讀取10顆棋的信息,若有連續(xù)5顆及以上為同色棋,則判定為贏。 以水平方向為例,倘若當(dāng)前的棋子為黑棋,先從右至左依次掃描該棋左邊的五顆棋,被掃描的棋子為黑棋,則計數(shù)器加一,否則停止掃描。然后從左至右掃描該棋右邊的五顆棋,處理方式同上。最終計數(shù)器的累計計數(shù)大于等于五,則可判定為贏
2)若勝負(fù)已分,在屏幕上顯示結(jié)果,除非開啟新局,否則不允許再次下棋:
a) 顯示結(jié)果:判定為贏后,加入文字顯示語句即可,具體如下:
ZiTiDuiXiang = pygame.font.SysFont('SimHei', 32)
WenBenKuangDuiXiang = ZiTiDuiXiang.render("Black win! once again(y/n)" if is_black else "White win! once again(y/n)", True, [0,0,0])
KuangDuiXiang = WenBenKuangDuiXiang.get_rect()
KuangDuiXiang.center = (300, 300)
screen.blit(WenBenKuangDuiXiang, KuangDuiXiang)
pygame.display.update()
b) 開啟新局前停止下棋:增加標(biāo)記flag=1, 置于鼠標(biāo)單擊判斷語句處,若勝負(fù)已分,則修改flag=0,此時單擊鼠標(biāo)便失效
c) 開啟新局或結(jié)束游戲:增加按鍵事件判斷,若按下y鍵,表明重新開局,修改flag = 1,同時重置棋面,如果按下其他鍵,則修改running = False,停止處理事件庫中的事件,并執(zhí)行到pygame.quit()語句,關(guān)閉游戲界面
3. 大球吃小球
要點:
1)吃球操作:增加方法eat(self, other) self代表指定球自身,而other代表球列表,注意,只有列表中的元素個數(shù)大于等于2時才可進(jìn)行吃球操作。順序掃描球列表中的元素,如果被掃描的球的半徑小于指定球,且兩個球的球心距離小于半徑之和,則執(zhí)行指定球吃被掃描球的操作,具體來說,先將兩球的面積相加,以此為基準(zhǔn)計算出一個新半徑并賦給指定球,最后從球列表中移除被掃描球,結(jié)束本次吃球操作。如果被掃描球的半徑大于指定球,且兩個球的球心距離小于半徑之和,則操作與上述相反
2)防止產(chǎn)生球的橫向或縱向速度為0:執(zhí)行下列代碼即可:
while sy == 0 or sx == 0:
sx, sy = randint(-10,10), randint(-10,10)
4. 貪吃蛇
要點:
1)判斷蛇是否吃到了自己:若吃到自己,也只能吃第四個節(jié)點以后的節(jié)點,所以從第五個節(jié)點開始遍歷,若被遍歷到的節(jié)點與頭節(jié)點的坐標(biāo)相同,則表明蛇吃到了自己,修改蛇的_is_alive屬性為False即可
2)吃食物計數(shù):設(shè)置一個專門計數(shù)的變量即可,至于計數(shù)的顯示,具體可參照五子棋的文字顯示方法。注意每局結(jié)束后計數(shù)要清零
3)食物的產(chǎn)生位置不能位于蛇身上:產(chǎn)生一個食物坐標(biāo),循環(huán)與蛇節(jié)點的每一個坐標(biāo)進(jìn)行比較,沒有相同的則成功,否則重新產(chǎn)生一個食物坐標(biāo)
下周將迎來網(wǎng)絡(luò)編程的學(xué)習(xí)及前一階段的考核,感覺并不慌,因為最終想做一個涉及機(jī)器學(xué)習(xí)、數(shù)據(jù)分析的大項目用作畢設(shè),希望老師在后期課程的講解過程中穿插推薦一些機(jī)器學(xué)習(xí)的自學(xué)方法及目前該領(lǐng)域的一些切實可行的創(chuàng)新點,筆者希望能提早為畢設(shè)做準(zhǔn)備,以免到時手足無措