Python每日一題:第2題
題目:設計一個猜數字的遊戲,系統隨機生成一個1~100之間的整數,玩家有5次機會,每猜一次系統就會提示玩家該數字是偏大還是偏小,如果猜中了,則告知玩家並提前結束遊戲,如果5次都沒猜中,結束遊戲並告知正確答案。
review完大家的程式碼,合併master分支,再把這篇文章寫法發現已經凌晨1點了,截止到10月30日總共有18人提交了程式碼,有少部分朋友還沒有學會如何使用GitHub,另外,每天出一個題對一部分人來說有點跟不上,所以為了能夠控制好我們的節奏,咱們每隔一天發一道題(改成每週1,3,5),這樣讓大家有更多的時間去學習,同時也方便我有更充足的時間來看大家的程式碼。
大家的程式碼主要有幾個問題:
1、函式、變數命名不規範
有些同學給函式、變數命名時,使用Java中的駝峰標識法,比如:guessNumber ,Python 官方的推薦寫法是要求函式名全部小寫,單詞之間採用下劃線連線,例如:guess_number。建議大家沒事多閱讀閱讀PEP8程式碼風格指南
2、while 條件語句不需要括號
有程式碼中把while的判斷語句用括號括起來,其實這是多餘的操作,在Python中,條件判斷語句不需要括號
while (chance == 4)
3、沒有對異常進行處理
很多人直接把使用者輸入的內容轉換為int,卻沒有對輸入值做判斷,如果輸入的是非數字,程式就崩潰了,顯然,如果在年會搞一個這樣的抽獎系統,那樣就糗大了。正確的做法應該是要對異常、邊界情況都要做判斷。
4、很多人的程式碼寫得不夠簡潔,比如引入了一些沒必要的臨時變數,沒有必要的 continue 關鍵字等等。
5、程式碼不夠抽象
程式碼不夠抽象是什麼意思呢?先來看這位同學寫的程式碼:
import random answer = random.randint(1, 100) i = 1 while i <= 5: guess = int(input("猜一個0到100的整數:")) if guess == answer: print('厲害了,猜對了!') break else: if guess > answer:print('猜大了!') else: print('猜小了!') chance = 5 - i print('再猜,還有%d次機會!' % chance) i += 1 print('遊戲結束,正確答案是:%d' % answer)
這段程式碼雖然能完成的任務,但是沒法靈活應對需求,在變化莫測的網際網路時代,如何把我們的程式碼寫得更靈活來應對產品的需求是程式設計師要思考的問題。比如這裡要求提高中獎機率(縮小隨機取值範圍、增加中獎次數),我們不得不修改整個程式碼,最好的程式碼就是在產品需求發生變化時,程式碼改動儘可能少,這就要求我們的程式碼寫得更抽象、更靈活。
我們來針對這段程式碼來進行重構,用面向物件的程式設計方式來實現,既然是面向物件,我們就要換一個角度來把問題抽象化,這個遊戲有4個屬性,分別是隨機數的取值範圍,min和max,目標值 target,猜測次數 choice,另有還有一個方法用於如何猜遊戲,隨著需求的變化,我們可以不斷地加其他屬性和方法。
import random class GuessGame: def __init__(self, min_num, max_num, choice): """ :param min_num: 最小值 :param max_num: 最大值 :param choice: 中獎機會 """ self.max_num = max_num self.min_num = min_num self.target = random.randint(min_num, max_num) self.choice = choice def guess(self): """ 猜數字 """ choice = self.choice while choice > 0: choice -= 1 try: num = int(input("輸入幸運數字:")) except ValueError as e: print("請輸入有效數字") continue if num == self.target: print("恭喜你猜中了") break elif num <= self.target: print("你猜的數字太小了,還剩 %d 次機會" % choice) else: print("你猜的數字太大,還剩 %d 次機會" % choice) else: print("很遺憾,%d 次機會都用完了,只差一點點就猜中了,正確答案是 %d" % (self.choice, self.target)) if __name__ == '__main__': game = GuessGame(1, 100, 5) # print(game.target) game.guess()
現在如果產品要求更改猜測的次數或者擴大隨機數的範圍,我們不需要修改這個類裡面的任何一行程式碼,只需要在呼叫的時候改變一下即可。話說回來,有時我們沒必要為了一個很小的功能而這樣去設計,但是,如果隨著這個遊戲的功能,複雜度越來越高的時候,這樣的設計就很有必要了。然而在真實場景中,需求是一點點往上加的,如果我們能站在更高的角度來思考問題,就能避免被產品牽著鼻子走,走在產品的前面,面對他們的需求遊刃有餘。
大家可以和自己的程式碼對比一下,可以看到我使用了python中特有的 while ... else 語法,在這樣的場景非常適合,免去了使用額外的標識變數來表示是否猜中,同樣還有 for ... else 和 try ... else 語法,大家可以總結下這些語法是如何使用的。
當然,現在離一個完整的程式還差一步,就是缺少單元測試,單元測試是保證程式碼質量的重要手段,大家方便的時候可以學習一下如何寫單元測試,把程式碼進行完善。
關注公眾號「Python之禪」(id:vttalk)獲取最新文章