迴圈這種東西呢在使用上,如剛剛所說,你使用 while,所以就是每跑一圈我們就會
去檢查一下你 while 後面的那個條件,那條件成立就繼續跑,條件不成立就跳出來。
所以某方面來講也蠻直觀的嘛,當某件事成立,你就
做...…做,做完再回去檢查當某件事成立,做...…做 不成立就跳出來。
但是呢,有時候我們要處理一些其他狀況,所以我們需要一些 工具,那我們現在要介紹的工具就是 break and
continue 這兩個關鍵字,那我們來試一下。
今天呢,我們在做 repetition process
的時候呢,我們可能要進一步地改變 我們程式執行的方式,那我們可能就會用到 break。
Break 可以幹嗎?一旦你在程式碼裡面 看到
break,它就會馬上跳出現在所在的迴圈。
換句話說呢 你不需要等到下一次檢查 while condition
的時候才有機會跳出迴圈, 你一看到 break 馬上就會跳出迴圈。
另外呢是 continue,如果我在迴圈裡面運作, 看到
continue 的時候我就會馬上跳過這之後的所有的東西,
然後跳回迴圈的開頭,去 check condition。
那如果成立的話就會繼續做,從頭開始做,不然呢,當然就會跳出去啦,所以這個稍微圖- 解一下。
如果你有一個 while,然後它有一個 condition
在這兒的話,你做啊做啊做啊做的 做到一句 continue
的話,那底下這一些就會被跳過, 你就會馬上回到
while 的開頭的地方去檢查這個 condition,對就繼續做
不對就跳出迴圈,所以 continue 大概是這個意思。
那如果是 break,如果這句話是 break 的話 那你就會馬上跳出迴圈,大概是這樣,好。
那這個懂了以後,我們來看一下可以幹啥用吧。
首先呢,我們來看一下左邊這個 program,左邊這個 program
一樣,它想做的事情又是去判斷 n 是不是 2 的冪次。
那它現在的演算法稍稍地有一點不同,那我們來欣賞一下。
首先呢,先輸入 這些基本資訊,但是這裡,m
現在讓它一開始的時候就是 n,而不是從一開始 我們剛剛是 m
一直變大...…變大,變大兩倍,等一下 m 要一直變小...…變小。
好,只要你的 m 還比 1 大,
我們就請你看看,m 現在除以 2 是不是可以整除。
如果 m mod 2,如果 m 除以 2 的餘數
不是 0 的話,那是什麼意思呢?比如說我是
31,31 除以 2 會等於 15,然後餘
1 嘛,這樣子,如果餘數不是 0 表示什麼?表示你 31
當然就不是 2 的冪次啦,你不要再做白日夢了,你再怎麼算 下去也不會有結果的,馬上就
break,那如果你沒有 break 的話,你會幹嘛?你會把 m
變小,變成一半大,然後再去做一次,然後再去做一次,然後再去做一次,所以我們看一下。
比如說呢,如果我輸入的是 30 好了,那 30
在一開始的時候呢,它還是餘 2 不是,它除 2 還是餘 0
的,所以你就會嘗試把它除以 2 變成 15,但是 15
再除就不行了, 所以你不會再嘗試再把它變小,不需要,所以呢你在一圈之內就可以跑出這個迴圈來,
然後你就知道 30 不是 2 的冪次。
那麼呢,這個跟剛剛的寫法比起來有什麼差別?很明顯地這個比較快,對吧? 因為剛剛如果是
30,是你的目標的話,你必須要 1, 2, 4, 8, 16,
32 你迴圈要跑 6 圈,你才會發現,30 不是 2 的冪次。
但我如果用除的,30 變 15 就不用再往下除了,因為
15 已經不是 2 的倍數了,那馬上就可以結束啦,那我們有興趣的同學可以試一下。
你如果輸入一個夠大的數字,而且這個程式碼跑夠多遍的話 就會顯出一些差別。
好,那右邊 這個 program 的話呢,大家仔細比較一下左邊跟右邊的話,
會發現,基本上就是 break 變成 continue
對吧?這裡寫著一個 break,這裡寫著一個 continue,
其他的部分呢長得都一模一樣,那會發生什麼事情?只要你這個還成立,而且如果你 比如說
15,除以 2 不是餘 0,對吧?因為餘 1 嘛,那你就 continue,continue
就會跳過底下的東西 再回去檢查,15 還是大於 1,那麼你又檢查,又跟剛剛一樣,什麼事情都沒有改變,因為
底下這兩行都被跳過了,所以你右邊的程式拿去跑,如果你輸入的東西 不是 2 的冪次的話,那不好意思你就會無窮迴圈。
好,所以這兩個 program 左邊這個 OK,而且很棒,相較於前面的這個的效率高多啦。
右邊那個呢,就是 logical error,這樣子。
好,那麼我們今天有一件事情要提醒大家, 就是說啊,break 跟
continue,它們的效益、 它們的效力,僅基於一層迴圈。
如果你看到 break,它發生在一個內層迴圈的話,它就會
跳到外層迴圈去,它不會一次跳出兩個迴圈,continue 的話一樣意思
它如果發生在內層迴圈的話,它會跳回內層迴圈的條件檢查的地方,而不是外層
迴圈的檢查的地方,所以呢我們大家可以看一下 這個例子,一開始
a 是 1,b 是 1,然後呢你有一個 while, 然後又有另一個
while,這個時候你忽然就理解了,這個想必就是叫做 nested
while, 巢狀迴圈,對吧?因為你剛剛
if 可以這樣 nested,那 while 當然也可以咯,好。
所以就是 a 如果小於等於 10,我就繼續做,b 如果小於等於 10,我就繼續做,然後呢,if
b 等於等於 5,那就 break,那一開始不是嘛,因為一開始是 1,所以我們就往下,我們就 print 一個東西。
print 完了以後我們就把 b 變大,所以 b 一開始是 1,然後就 2,然後就 3,然後就 4,然後就
5, 當 b 是 5 的時候我們會執行到這一行 break,請問這個時候
我們會跳出的是這個迴圈還是這個迴圈呢?答案是裡面那個,因為我們 break
只會 跳出一層迴圈,所以當執行到這個 break 的時候,我們是會跳出這個
inner while 然後我們就會,對不起,我們就會跳出
這一個 inner while,然後我們會去把 a 加 1,然後再繼續
跑外層迴圈,然後再進入內層迴圈,然後再以此類推,那這裡我就不把它推完了。
大家有興趣可以自己去試一下,看看如果跑完的話,會發生什麼事情。
如果你能完全解釋剛剛那個程式碼,那你應該就算是懂得相當多啦。
好,那既然我們有 break 可以用,那有的時候我們就會
在程式裡面自顧自地寫出 infinite loop,因為
我們現在要做的事情是我們要用 break 來 terminate 我們的 loop,而不是用
while 的 condition,那麼呢我們就來看剛剛那個,讓使用者輸入他要不要離開的這個例子。
先看上面這個框框,剛剛是說啊,使用者玩啊玩啊玩的,最後你問他 請問你要離開了嗎?然後呢他就說是或不是,
他如果說他還沒有要離開,你就讓他繼續玩,然後再問他一次,剛剛是這樣的寫法。
那我現在說,好,咱們來改成這樣,下面這個是什麼呢?無論如何就讓他一直玩...…- 一直玩。
玩到最後,問他,請問你要離開嗎?如果他輸入的是 y
或者是 Y,我們就離開,這樣子。
好, 仔細閱讀一下這兩個 program 的話,你會發現它們的效果是
一樣的,使用者都會先玩一玩,然後被問要不要離開。
好,先玩一玩,然後被問要不要離開。
然後同樣的都是,如果他說不,那就會繼續玩,然後再來問 如果他說要,那就會離開,但是下面這個
program 在這個例子里是比較好的,因為
if 怎樣怎樣就怎樣,這件事情比較直觀,上面是
while 不是怎樣 的時候就怎樣怎樣,不管怎麼樣,這個
negative condition,這個負的 condition 你人要理解會稍微
比較不直觀一點,所以下面這個相對 可讀性和直觀的理解程度都比較高。
那其次呢,就是說,上面這個程式碼有我們最痛恨的 potential
inconsistency,就是我劃紅線的這兩段,又是複製貼上的。
那如果你今天要改其中一個,忘了改另外一個,就會非常地麻煩,所以我們
也不建議你寫上面這一種,在這個例子里,下面這種就沒有 potential inconsistency。
那這個寫起來呢,就效果確實是比較好啦。
所以呢,我們今天,我們知道,當我們在使用 這個所謂的這個
while 迴圈在做現在這個動作的時候,我們
出現了 potential inconsistency,那也就是所謂的 redundant codes,
就是照理說是不需要連續出現兩邊才對的。
我呢只出現一邊就好啦,那這個就是 我們在這個例子里使用 break 的理由。
那麼 redundancy 就如我們剛剛所說的,它會帶來 potential 的 inconsistency,所以希望大家可以盡量地避免。
那在某一些程式語言裡面呢,有一種叫做 do while 的 loop,那
Python 裡面沒有,所以我們就不特別介紹了, 但是至少你知道,要消滅這種
potential inconsistency 是大家的共識,所以有 do while
這種機制 出現,Python 沒有,所以你自己做,怎麼做?就是前一頁
的 while true,你就一直跑...…一直跑,
但當某件事情發生你就離開,那這樣子就可以達到一樣的效果啦。
好,最後做點 remark,就是說呢,break
固然是好,但它有一個缺點 就是你的 loop 會有很多個結束
loop 的方式,如果你的 loop 裡面沒有 break
的話, 那麼你知道,只要你這個東西跳出迴圈,那必然就是
while 後面的 condition 被違反了,所以呢它對於你在跳出
迴圈的時候,你環境上什麼樣子,你現在程式進行到什麼狀態 有一些資訊量,因為你知道
while 後面的 condition 一定是被違反的。
但今天如果有 break 在你的程式碼裡面的話,那就不一定了。
你不能保證它是 break 跳出來的,還是 while 的 condition 跳出來的嘛,都有可能,你就必須要做更仔細的 檢查才行。
所以呢,就會變成比較難去 check 我們的程式是怎麼跑的。
比較難去知道我們跑出了迴圈以後程式的狀態是怎麼樣的。
相較之下呢 continue 有的時候覺得蠻沒用的,但是 continue
其實有時候是 對於進入下一個 iteration,進入下一圈迴圈
是有一個 highlight 的效果,所以我們在閱讀程式碼的時候呢,有時候也是可以利用
continue 來做這個 highlight 做這個強調的動作。
但 again,你如果用太多的話,恐怕使用者也是會覺得很複雜。
所以最好也是不要濫用啦,這樣子。
總而言之,我們在做任何事情的時候呢
都需要兼顧到可讀性,那你漸漸地也會發現,要不是因為我們想要顧慮可讀性的話,
很多功能都根本不需要對你介紹,因為你其實用最基本的功能就可以
組合出很強大很複雜的函數了,就可以寫出很厲害的程式 只是很麻煩,只是很難維護而已。
所以為了要好 維護,為了要好擴充,我們需要有好的可讀性,
才會介紹你各式各樣更多的功能。