2023-08-25|閱讀時間 ‧ 約 5 分鐘

低調但有料的for... else語法

因應原書於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)


少了那根旗子,嗯,感覺上清爽多了!

分享至
成為作者繼續創作的動力吧!
© 2024 vocus All rights reserved.