因應原書於2024年改版後授權範圍改變,故改版為《The Nature of Code閱讀心得與Python實作》。
文中提到的練習題,在改版之後已刪除。
寫《The Nature of Code閱讀心得筆記——使用Python實作》第二章的第七節摩擦力部分時,有個練習題,是要在畫面中創造一些口袋區域。這些口袋區域有個特性,就是當物體不在其中時,會受到重力和風力的作用,但當物體穿過其中時,就只會受到摩擦力的作用。另外,每個口袋區域的摩擦係數不同,所以物體在不同的口袋區域,感受到的摩擦力會不一樣大。
假設在畫面中跑來跑去的物體叫mover,而所有的口袋區域都放在pockets這個list中。因為要讓mover在口袋區域內和口袋區域外所受的作用力不同,所以必須先檢查mover是不是在某一個口袋區域內,然後再決定哪種作用力會作用在它身上。順著這個思路,主程式的架構可以寫成這樣:
in_pocket = False
for pocket in pockets:
if mover.isinside(pocket):
in_pocket = True
mover.apply_force(friction)
break
if not in_pocket:
mover.apply_force(gravity)
mover.apply_force(wind)
這樣的寫法雖然沒什麼問題,可是不管怎麼看,都覺得拖泥帶水、醜不啦嘰的,實在是讓人沒法就這麼let it be。尤其是那個in_pocket,不知道為什麼,看了就討厭,總覺得欲除之而後快。
其實以前碰到類似問題的時候都是這麼寫的。用迴圈搭配條件判斷,來看看一大堆東西中,是不是有符合條件的。如果有,就做這件事;如果都沒有,就做那件事。但迴圈結束之後,要怎麼知道到底有沒有符合條件的?那就只好用根旗子(flag)來紀錄檢查的結果,如果有符合條件的,就把旗子豎起來。前面程式中的in_pocket,就是這個作用。
說來奇怪,以前使用其他程式語言時,這樣寫都不覺得怎樣,可是現在用python這樣寫,卻覺得很彆扭,看著程式,總覺得那根旗子實在是很礙眼。
看著那根旗子好一會兒,忽然覺得,似乎、彷彿、好像、應該有個for... else語法,可以讓程式漂亮一點。
「還真的有耶!」當真的確定有for... else語法的時候,還真是打從心裡讚嘆了一下。說真的,先前完全不記得有看過這個語法,所以當確定它的確存在時,實在覺得挺神奇的。或許這就跟張三丰教張無忌太極拳一樣,一直到張無忌說全忘光了,張三丰才認為張無忌已經學會了。以前應該有看過for... else這個語法,可是已經沈潛到潛意識中而忘掉了,等到臨陣對戰有需要的時候,那蟄伏在潛意識中的記憶,自然而然就甦醒了。所謂的「靈感」,或許也就是這麼回事吧。
那這個for... else語法,到底是怎麼個運作法呢?來看看下面這段程式:
for i in box:
if i > 10:
print(i)
break
else:
print('The End!')
如果
box = [1, 9, 15, 8, 18, 2, 0]
這段程式執行之後,會印出數字「15」。但如果
box = [1, 9, 5, 8, 3, 2, 0]
則執行之後,會印出「The End!」。從這樣的結果可以知道,這個for就是平常for迴圈的for,沒啥特別的。但是,當for執行完之後,會繼續執行else後面的東西。如果不想要執行else後面的東西,那就在for裡頭用break跳出整個迴圈。
利用for... else語法,那個練習題主程式的架構,可以改寫成這樣:
for pocket in pockets:
if mover.isinside(pocket):
mover.apply_force(friction)
break
else:
mover.apply_force(gravity)
mover.apply_force(wind)
少了那根旗子,嗯,感覺上清爽多了!