但突然間我改變了心意。突然間,我決定我真正該做的是什麼。我差不多該要離開這個迴圈了,就在今天晚上。
~節錄自《賴田捕手》第七章
經過前兩天的努力,我們已經學會 Python 中基本的,也是最常用的資料結構,包括清單(list)、不可變更清單(tuple)、字典(dict)、集合(set)。我想要講,卻還未能講清楚的物件,就只剩下函數(function)了。在 Python 中,函數就像是一篇文章,或是一個小品。你寫出一段又一段的程式碼,把它們用函數包裝起來,賦予它們機動性。讓你可以輕鬆的把它們塞進口袋,帶著它們環遊世界。好比說,在 101 閃耀的 LED 燈光照射下,靠著陽台,拿出來好好品味一番。
要寫出優美動人的文章,除了要有一顆多愁善感的心,還必須有打磨過後洗鍊的表達技巧才行。也就是說,我們要熟悉撰寫文章的語法。那麼就先來講講 Python 當中常用的幾種句型吧!
if
、elif
、else
) 第一個要介紹的句型是如果,不然。如果大家還受得了的話,我就繼續來分享我家草泥馬的生活點滴囉!不然,我來講些比較學術性的東西好了。
草泥馬其實是很有求知慾的生物。我住的地方累積了不少以前上學時,學校發下來的課本或老師發的講義,書架上、床底下、衣櫃裡,堆得滿滿滿。有一次在整理裝箱的時候,正巧被草泥馬看到。那隻草泥馬,當時因為腸胃不適的關係,總是沒什麼精神。結果意想不到的事情發生了。就著零零落落散落一地的教科書,牠居然乖乖盤腿坐下,聚精會神,一本一本地啃了起來。啃,就是字面上的意思,嚼食。原來教科書非常幫助消化啊!
從此以後,教科書就成了草泥馬們最愛的零嘴。牠們尤其喜歡數學相關的教科書。原本我有滿滿一整架書櫃的數學課本、參考書、講義、習題、考卷,被牠們每天大嚼特嚼,大概只剩下不到一成了。糟糕,總不能叫我回去當學生再收集一些數學課本吧?因此我試著讓牠們珍惜數學課本,嘗試讓牠們了解到數學課本是拿來讀的,不是拿來啃的,希望可以讓牠們戒掉這個奇怪的嗜好。效果出奇的好。我從加法開始教起,教到減法、乘法、除法,牠們已經開始有一點基本的數學概念了。最近在學的是質數。所謂的質數,就是除了 1 跟這個數字本身,沒有其他數字可以整除它的,就叫質數。舉例來說,所有的偶數裡面,只有 2 是質數。其他的偶數都會被 2 整除,因此不屬於質數。
In [1]: number = 10
if (number % 2 == 0):
print('An even number. Not a prime number.')
else:
print('An odd number.')
An even number. Not a prime number.
上面那段程式碼,就是if``else
最基本的運用。
number = 10
if (number % 2 == 0):
if
的起手式。中文翻譯就是:如果我們想要測試的數字除以 2 的餘數等於 0 的話,就執行下面的程式碼。if
後接的是一個判斷語句,該語句會回傳True
或是False
。接著用一個冒號承先啟後,意指判斷句到此結束,若判斷句回傳True
,則執行下列程式碼。這個例子裡,我們的判斷語句是(number % 2 == 0)
。要不要在前後加上括號()
隨便你,也可以用if number % 2 == 0:
就好。 print('An even number. Not a prime number.')
True
,就執行這行程式碼。需要注意的是,這行程式碼前面用了 4 個空白鍵當作縮排。縮排是Python中相當重要的概念,用來標明程式碼的歸屬。大原則是,每一個:
後面,都有一個往內縮排的段落,代表附屬的程式碼。只有當:
前面的條件被滿足時,才會執行。Python給了我們自行定義縮排的方式,只要在同一份檔案裡面都採用相同的格式就行。你可以用 2 個空白鍵當作縮排,也可以用 100 個空白鍵當作縮排。習慣上,大多數的人選用 4 個空白鍵當作縮排。偶爾也會看到有些人用 2 個空白鍵當作縮排的。但我還沒看到有人嘗試用 100 個空白鍵當作縮排。大家有興趣的話,可以當作引領風騷的第一人。另外,不要把空白鍵跟tab鍵混著使用。如果你用 4 個空白鍵當作縮排了,就不要偷懶偷偷用 tab 鍵,會出事。else:
if
後面的判斷句回傳的是False
,就執行else:
下面的程式碼。因為這行程式碼,並不屬於if
,並不是if
條件成立之後該執行的程式碼,因此你可以看到,跟第二行的if (number % 2 == 0):
一樣,前面只有 0 個空白鍵。 print('An odd number.')
else
條件成立該執行的程式碼。前面有 4 個空白鍵當作縮排。解說完了之後,再回過頭來看程式碼,有比較好懂了嗎?再舉一例。每當樂透彩連續槓龜好多期,獎金上看好多億的時候,都市流言就會開始在辦公室裡蔓延開來,說,如果明天大樂透開獎,沒看到某某某出現在辦公室,你就知道以後白吃白喝可以找誰了?但很可惜我總是沒有機會可以成為別人的靠山。
In [2]: 我中了樂透 = False
if 我中了樂透:
print('明天我就不來上班了!')
print('而且不用再擔心草泥馬的伙食費了!')
else:
print('明天還得繼續來上班...')
print('繼續為草泥馬的伙食費打拼...')
明天還得繼續來上班...
繼續為草泥馬的伙食費打拼...
但是真實的情況可能更加複雜。我雖然這期沒中,但如果這次的頭獎也沒開出來的話,我就還有中大獎的機會,還可以去投注站繼續購買彩券。
In [3]: 我中了樂透 = False
這期開出頭彩 = False
if 我中了樂透:
print('明天我就不來上班了!')
print('而且不用再擔心草泥馬的伙食費了!')
elif 這期開出頭彩:
print('明天還得繼續來上班...')
print('繼續為草泥馬的伙食費打拼...')
else:
print('明天還得繼續去投注站報到...')
print('有買有希望!')
print('...')
print('不管如何,日子總要繼續過下去。')
Out[3]: 明天還得繼續去投注站報到...
有買有希望!
...
不管如何,日子總要繼續過下去。
解釋一下上面那段程式碼。首先,判斷if
後面的條件是否回傳True
。結果是令人難過的False
。所以就不能執行附屬於if
的那些程式碼。接著用elif
做第二個判斷,只有在第一個if
回傳False
的情況下,才會開始這個判斷。結果是讓人充滿希望的False
。所以也不需要執行附屬於elif
的程式碼。然後,在if
跟elif
都回傳False
的情況下,執行附屬於else
的程式碼。
最後兩行,因為沒有使用縮排,不附屬於任何一種情況,所以不管上面執行了哪一段程式碼,在做完if
、elif
、else
等等的判斷之後,都會被執行。不管如何,日子總要繼續過下去的!
這邊講一下判斷句使用的運算符號。還記得一開始的number % 2 == 0
嗎?為什麼不是用number % 2 = 0
呢?因為只用=
,是貼標籤的意思,硬要這樣寫的話,就會變成:「把number % 2
這個標籤貼在整數物件0
上」。當然是錯誤的用法。為了區隔數學上的等號,跟 Python 中的貼標籤,在 Python 中,等於會表示為==
。表一列出了常用的判斷句運算符號。
表一、常用的判斷句運算符號
運算 | 運算子 |
---|---|
等於 | == |
不等於 | != |
小於 | < |
大於 | > |
小於等於 | <= |
大於等於 | >= |
在...之中 | in |
第二個要介紹的句型是當。當(while)會產生一個迴圈結構,只要條件滿足,就會重複執行回圈內的程式碼。
在試著教導草泥馬數學的同時,我才漸漸體會到為人師表的苦衷。老師心裡苦,只是老師不說。我自認為是個很有耐心的人,從 1 分到 10 分的話,我給我自己的耐心打 10 分。但是但是,當我在講質數的定義講得口沫橫飛的時候,草泥馬們卻在一旁竊竊私語聊起天來,不聽就算了,還老是不學會,我的耐心真的會被草泥馬用完。
In [4]: 我的耐心 = 10
竊竊私語 = 0
while 我的耐心:
竊竊私語 += 1
print('草尼馬低頭聊天第', 竊竊私語, '次')
我的耐心 -= 1
草尼馬低頭聊天第 1 次
草尼馬低頭聊天第 2 次
草尼馬低頭聊天第 3 次
草尼馬低頭聊天第 4 次
草尼馬低頭聊天第 5 次
草尼馬低頭聊天第 6 次
草尼馬低頭聊天第 7 次
草尼馬低頭聊天第 8 次
草尼馬低頭聊天第 9 次
草尼馬低頭聊天第 10 次
上面那段程式碼,紀錄了我的耐心漸漸用完的過程。
我的耐心 = 10
n = 0
while 我的耐心:
if
一樣,while
後面是一個判斷語句,如果回傳True
,就執行附屬於while
的程式碼,如果回傳False
就結束while
迴圈。 竊竊私語 += 1
print('草尼馬低頭聊天第', 竊竊私語, '次')
我的耐心 -= 1
這邊要特別說明一下的是第三行while 我的耐心:
。我用'我的耐心'
當作判斷語句,負責傳回True
或是False
。咦?'我的耐心'
明明是整數物件,怎麼會傳回True
或是False
呢?原來 Python 相當聰明,他知道接在if
、elif
、或是while
後面的判斷語句,需要負責回傳True
或False
,因此自動把這些物件都布林化了。所以寫成 while 我的耐心:
,其實就等同於while bool(我的耐心):
。不知道大家是否還依稀記得,如何把既有物件布林化,創造出一個布林物件呢。可以回頭看看第 03 天的內容喔。絕大多數的物件,經過布林化之後,都會回傳True
。只有特別幾種狀況會變成False
。表二列出這些特別的狀況。
表二、布林化後會傳回False
的物件
物件類型 | 程式碼 |
---|---|
布林(boolean) | False |
整數(integer) | 0 |
浮點數(float) | 0.0 |
空清單(list) | [] |
空不可變更清單(tuple) | () |
空字典(dictionary) | {} |
空集合(set) | set() |
我的合作夥伴在一旁看到我的教學慘況,決定接手幫忙。他是個麻木無感的傢伙,即使草泥馬們在他教課途中竊竊私語,甚至大聲嬉鬧,他也不為所動。但我在旁邊實在看不下去了,雙手一揮,終止了今天的課程。不管如何,都得給願意花時間教你知識的人一些尊重吧。
In [5]:合作夥伴的耐心 = 10
竊竊私語 = 0
while 合作夥伴的耐心:
竊竊私語 += 1
print('草尼馬低頭聊天第', 竊竊私語, '次')
if 竊竊私語 > 15:
print('==無用學習==')
break
草尼馬低頭聊天第 1 次
草尼馬低頭聊天第 2 次
草尼馬低頭聊天第 3 次
草尼馬低頭聊天第 4 次
草尼馬低頭聊天第 5 次
草尼馬低頭聊天第 6 次
草尼馬低頭聊天第 7 次
草尼馬低頭聊天第 8 次
草尼馬低頭聊天第 9 次
草尼馬低頭聊天第 10 次
草尼馬低頭聊天第 11 次
草尼馬低頭聊天第 12 次
草尼馬低頭聊天第 13 次
草尼馬低頭聊天第 14 次
草尼馬低頭聊天第 15 次
草尼馬低頭聊天第 16 次
==無用學習==
一樣來講解一下程式碼
合作夥伴的耐心 = 10
竊竊私語 = 0
while 合作夥伴的耐心:
竊竊私語 += 1
print('草尼馬低頭聊天第', 竊竊私語, '次')
誰知道我的合作夥伴是個超無感的人,他的耐心完全不受影響,但我看不下去了。
if 竊竊私語 > 15:
print('==無用學習==')
break
這邊我們用到了一個新東西break
。在while
迴圈,或是等等會介紹到的for
迴圈裡,碰到break
,不管三七二十一,就是會終止這個迴圈的運作。
另外還有個有趣但不太直覺的東西。Python有if
、else
這種句型組合,也有while
、else
這種句型組合。while
、else
裡面的else
怎麼作用呢?這裡的else
可以當作 break checker 來使用,檢查剛才跑完的while
迴圈是否是被break
強制結束的。如果while
迴圈是被break
強制結束,就不會執行else
附屬的程式碼。如果while
迴圈跑完了,中間都沒有碰到break
,就會進入else
,執行附屬於else
的程式碼。我們把上面的程式碼拿來修改一下看看。
In [6]: 我的耐心 = 10
竊竊私語 = 0
while 我的耐心:
竊竊私語 += 1
print('草尼馬低頭聊天第', 竊竊私語, '次')
我的耐心 -= 1
else:
print('我的耐心用完了...')
草尼馬低頭聊天第 1 次
草尼馬低頭聊天第 2 次
草尼馬低頭聊天第 3 次
草尼馬低頭聊天第 4 次
草尼馬低頭聊天第 5 次
草尼馬低頭聊天第 6 次
草尼馬低頭聊天第 7 次
草尼馬低頭聊天第 8 次
草尼馬低頭聊天第 9 次
草尼馬低頭聊天第 10 次
我的耐心用完了...
我的合作夥伴呢?
In [7]: 合作夥伴的耐心 = 10
竊竊私語 = 0
while 合作夥伴的耐心:
竊竊私語 += 1
print('草尼馬低頭聊天第', 竊竊私語, '次')
if 竊竊私語 > 15:
print('==無用學習==')
break
else:
print('合作夥伴的耐心用完了...')
草尼馬低頭聊天第 1 次
草尼馬低頭聊天第 2 次
草尼馬低頭聊天第 3 次
草尼馬低頭聊天第 4 次
草尼馬低頭聊天第 5 次
草尼馬低頭聊天第 6 次
草尼馬低頭聊天第 7 次
草尼馬低頭聊天第 8 次
草尼馬低頭聊天第 9 次
草尼馬低頭聊天第 10 次
草尼馬低頭聊天第 11 次
草尼馬低頭聊天第 12 次
草尼馬低頭聊天第 13 次
草尼馬低頭聊天第 14 次
草尼馬低頭聊天第 15 次
草尼馬低頭聊天第 16 次
==無用學習==
上面那兩段程式碼當中,只有第一段跑完while
迴圈都沒碰到break
,因此執行了else
裡面的程式碼。
「好了好了不要生氣,」我的合作夥伴勸我,說我教學沒有技巧,而他教學又沒有熱情,當然激不起草泥馬們的學習興致。聽他這麼一說,好像也有道理,於是,經過不斷嘗試跟修正之後,草泥馬們終於慢慢肯專心聽課了。現在我講課都從簡單的開始,多舉幾個例子,確定草泥馬們都理解之後,再慢慢帶入新觀念。
「2 到 10 裡面,只有 2、3、5 是質數。那麼你們可以說說看, 2 到 10 裡面,不是質數的有哪些呢?」我試著循循善誘。
In [8]: prime_list = [2, 3, 5]
n = 2
while n <= 10:
if n in prime_list:
pass
else:
print(n)
n += 1
4
6
7
8
9
10
上面那段程式碼的第五行,我用了一個pass
。這可以做什麼呢?答案是,什麼都不做。我用了一個if
的判斷句,所以要有一段附屬於if
的程式碼,告訴Python當符合if
的條件後,該執行些什麼。這次我們沒特別想做什麼,想來想去,只好說出pass
。程式碼跑起來的感覺大概是這樣的:
while
的條件(n <= 10
),就開始一次while
的迴圈→當符合if
的條件,就執行附屬於if
的程式碼,也就是什麼都不做,pass
→執行n += 1
之後,來到while
迴圈的盡頭,完成一次while
迴圈→while
的條件(n <= 10
),就開始一次while
的迴圈→當不符合if
的條件,就執行附屬於else
的程式碼,也就是print(n)
→執行n += 1
之後,來到while
迴圈的盡頭,完成一次while
迴圈→while
的條件(n <= 10
),離開while
迴圈。 這就是pass
的作用。好像用處不大啊?是的,聰明的你,說不定已經發現,上面那段程式碼,其實有不需要pass
的寫法:
In [9]: prime_list = [2, 3, 5]
n = 2
while n <= 10:
if n not in prime_list:
print(n)
n += 1
4
6
7
8
9
10
太聰明了!那麼聰明的你,是否發現,上面那段程式碼,其實有需要continue
的寫法:
In [10]: prime_list = [2, 3, 5]
n = 1
while n < 10:
n += 1
if n in prime_list:
continue
print(n)
4
6
7
8
9
10
這邊在程式碼的第六行,我用了continue
。這個東西有點神妙。它代表這次的迴圈執行到這就好,剩下的都不要管,嘗試開始下一次迴圈吧。以上面那段程式碼為例,運作起來的感覺大概是這樣的:
while
的條件(n <= 10
),就開始一次while
的迴圈→執行n += 1
→當符合if
的條件,就執行附屬於if
的程式碼,也就是continue
,剩下的程式碼不要管,直接來到while
迴圈的盡頭,完成一次while
迴圈→while
的條件(n <= 10
),就開始一次while
的迴圈→當不符合if
的條件,就執行附屬於else
的程式碼(這邊沒有else
,所以什麼都不需要做)→執行print(n)
之後,來到while
迴圈的盡頭,完成一次while
迴圈→while
的條件(n <= 10
),離開while
迴圈。 試著現學現賣,把剛才提到的東西比較一下。break
是馬上離開這個迴圈,而continue
則是馬上開始執行下一次的迴圈(如果迴圈的起始條件能被滿足)。pass
是什麼都不做,當我空氣就好。
對於(for)是今天會學到的最後一個句型。for
也是一種迴圈。不囉嗦,直接來看程式碼。
In [11]: prime_list = [2, 3, 5]
n = 1
for i in prime_list:
print('prime_list 中的第', n, '個數字:', i)
n +=1-
prime_list 中的第 1 個數字: 2
prime_list 中的第 2 個數字: 3
prime_list 中的第 3 個數字: 5
上面那段程式碼就是for
的基本運用。讓我慢慢解釋一次:
prime_list = [2, 3, 5]
prime_list
。n = 1
n
,等等當作計數器來用。for i in prime_list:
for
迴圈的開始。直接翻譯,其實這行程式碼要說的就是:「對於在prime_list
中的物件i
」。prime_list
中有哪些物件呢?我們知道有三個物件,分別是2
、3
、5
。用Python的語言來說,就是prime_list[0]
、prime_list[1]
、prime_list[2]
。因此可以預見,如果沒有break
的意外,這個for
迴圈會跑 3 次。第一次,i = prime_list[0]
,第二次,i = prime_list[1]
以此類推。 print('prime_list 中的第', n, '個數字:', i)
print
紀錄當下n
跟i
的值。 n +=1
n
就增加1
。 因為計數器太常在程式中被用到了,為了方便辛苦撰寫程式碼的碼農們,Python也提供了自己的計數器enumerate()
。
In [12]: prime_list = [2, 3, 5]
for n, i in enumerate(prime_list, 1):
print('prime_list 中的第', n, '個數字:', i)
prime_list 中的第 1 個數字: 2
prime_list 中的第 2 個數字: 3
prime_list 中的第 3 個數字: 5
讓我們來瞧瞧enumerate()
怎麼運作的。
for n, i in enumerate(prime_list, 1):
n = 1
計數器也可以不用了。先來翻譯一下:「對於在enumerate(prime_list, 1)
中的n
和i
」。enumerate(prime_list, 1)
會回傳兩個東西,第一個回傳的是編號,就是我們想要用的計數器。既然是編號,那麼要從幾號開始呢?我們告訴enumerate()
請從1
開始。順帶一提,如果什麼都不指定的話enumerate(prime_list)
,那麼編號就會從0
開始。第二個回傳的則是prime_list
中的物件。一樣,第一次迴圈傳的是prime_list[0]
,下一個迴圈是prime_list[1]
,以此類推。enumerate(prime_list, 1)
一次會傳回兩個東西,第一個是編號,我們把編號用標籤n
貼上。第二個則是prime_list
中的物件,我們把它用i
貼上。然後開始進入附屬於for
的程式碼,跑一次迴圈。 既然提到了手指的疲勞,就不能不說一下分憂解勞、居家必備的range()
,先來看一段程式碼:
In [13]: for i in range(11):
if i not in prime_list:
print(i)
0
1
4
6
7
8
9
10
for i in range(11):
range(11)
中的i
」。再白話一點:「對於在範圍11
中的i
」。範圍11
,聰明的你可能已經猜到了,就是從0
開始(包含0
),到11
為止(不包含11
),範圍內的所有整數。原本想要做到同樣的效果,可能需要先創造個清單[0, 1, 2, 3, 4, …, 10]
,現在只要一個range(11)
。怎麼樣,夠紓壓了吧?In [14]: for i in range(2, 11):
if i not in prime_list:
print(i)
4
6
7
8
9
10
range(2, 11)
代表的是「從2
開始(包含2
),到11
為止(不包含11
),範圍內的所有整數」。那麼如果我想要來個間隔呢?哈哈哈,太小看大家了,還不就是range(開始的x, 結束的y, 間隔的z)
。正確答案!
好啦,說了那麼多,今天的課程總算要結束了。但講來講去,草泥馬們好像都還是只聽到 1 到 10 當中有哪些質數而已啊。有一些好學的草泥馬,已經開始吱吱喳喳吵著要知道更多的質數了呢!不然這樣,我們來教牠們怎麼自己尋找質數好嗎?
質數的定義是,只能被 1 跟本身整除的數。➀ 檢查一個數是不是質數,只要沒有一個比它還小的數可以整除它,這個數就是質數。更簡化一點,到這個數的開根號為止,只要沒有一個數可以整除它,這個數就是質數。舉例來說,對於23,只要檢查到 4 (23 開根號大約是 4.79 ),都沒有數字可以整除 23,那麼就可以斷言 23 是個質數了。
大家可以先試著自己寫寫看,如何請 Python 幫忙找質數。
下面是我的版本,試著找出從 2 到 100 中間的所有質數:
In [15]: start = 2
end = 100
prime_list = []
for i in range(start, end+1):
j = 1
while j < int(i**0.5):
j += 1
if i % j == 0:
break
else:
prime_list.append(i)
prime_list
[2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97]
上面我用一個for
搭配while
寫的。大家也可以試試看其它種寫法。下面偷渡一個函數(function)物件:
In [16]: def find_prime(end, start=2):
prime_list = []
for i in range(start, end+1):
j = 1
while j < int(i**0.5):
j += 1
if i % j == 0:
break
else:
prime_list.append(i)
return prime_list
In [17]: find_prime(100)
[2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97]
明天我們就要來講函數物件了。不知道大家會不會滿臉疑惑,為什麼講了老半天還在 Python 呢?當然是因為 Python 很有趣啊!好啦,說正經的:因為草泥馬很可愛啊!我在這邊大膽許下一個願望,希望我們可以在第 10 天實作出第一個 LINE 聊天機器人。加油吧大家!今天的用到的程式碼在這(Github 或 nbviewer)。大家也可以參考 Introducing Python 的讀書筆記,謝謝大家!
##參考資料
➀ 質數 wiki
➁ Introducing Python 讀書筆記 第四章
註:對於此系列文有興趣的讀者,歡迎參考由此系列文擴編成書的 LINE Bot by Python,以及最新的系列文《賴田捕手:追加篇》
第 31 天 初始化 LINE BOT on Heroku
第 32 天 快速回覆 QuickReply 介紹
第 33 天 妥善運用 Heroku APP 暫存空間
第 34 天 妥善運用 LINE Notify 免費推播
第 35 天 製造 Deploy to Heroku 按鈕
您好,我剛開始學習python也沒有其他程式語言基礎,想先謝謝您的教學分享,不知道能提問嗎?
我想請問質數的部分,既然<只要沒有一個比它還小的數可以整除它,這個數就是質數>,那程式碼是否也可以不需要將i開根號?
我試著把**0.5去掉後執行程式碼,結果list內是空的
然後.. 我想請問if i % j == 0: 是什麼意思,我想了兩個禮拜還想不懂這行的意思(很笨QQ)
還有請問else:為什麼不是跟if i % j == 0:同階層
謝謝
您好
感謝您的閱讀。第一次學程式語言一般都會花比較多的時間來熟悉,每個人都有自己的一套學習方式。我習慣先弄清楚程式語言提供的資料型別 (type) 有哪些,各種資料型別的操作方式,以及語言所提供的各種句型,也就是控制流 (control flow),這些都弄懂之後,一些簡單的程式碼大概都能夠看懂,要繼續自學也會更有效率。
因此我也就先按照這樣子的邏輯來回答您的問題。
完整的程式碼是這樣:
def find_prime(end, start=2):
prime_list = []
for i in range(start, end+1):
j = 1
while j < int(i ** 0.5):
j += 1
if i % j == 0:
break
else:
prime_list.append(i)
return prime_list
這個程式碼當中,i
跟j
都是 Python 數字型別 (number) 的物件。既然是數字,當然可以藉由加減乘除來做運算。讓我們看看 Python 當中提供給數字的運算能力:
運算 | 運算符號 | 範例 |
---|---|---|
加法 | + |
2 + 3 = 5 |
減法 | - |
2 - 3 = -1 |
乘法 | * |
2 * 3 = 6 |
浮點數除法 | / |
13 / 5 = 2.6 |
整數除法 (商數) | // |
13 // 5 = 2 |
餘數 | % |
13 % 5 = 3 |
次方 | ** |
2 ** 10 = 1024 |
所以i ** 0.5
就是i
的0.5
次方,也就是把i
開根號。而i % j == 0
這個判斷式,就是在判斷i
能否被j
整除。
Python 提供了各式各樣的句型,其中一種叫做for
-else
以及while
-else
。這一種用法不太常見,不過非常有趣,從「字面」上來看應該無法理解這個句型在做什麼。把這種句型想成是break
驗證機制,也許比較好懂。
在for
或者while
迴圈當中,加入break
,如果執行到break
,那麼就會直接結束所有迴圈,如:
for i in range(5):
if i == 2:
break
print(i)
0
1
單純的for
迴圈,會讓i
從0
一直數到4
。然而我們在迴圈當中加入break
,當滿足條件i == 2
,break
執行,整個迴圈就嘎然而止了。那麼什麼叫做for
-else
呢?for
仍舊是一般的迴圈,而else
代表一段只有完整跑完for
迴圈才會被執行的程式碼。也就是說:
for i in range(5):
if i == 2:
break
print(i)
else:
print('我不會被執行')
0
1
因為我們的for
迴圈被break
給打斷了,所以else
裡面的程式碼就跟著被跳過。但如果for
迴圈被完整執行:
for i in range(5):
if i == -1:
break
print(i)
else:
print('我被執行了')
0
1
2
3
4
我被執行了
這就是所謂的for
-else
,break
驗證機制。同理,while
-else
也是這樣運作。
最後來看看,為什麼把int(i ** 0.5)
改成int(i)
,就找不到質數了呢?
答案是,因為我們先執行了j += 1
,接著才檢查i % j == 0
,所以不管是哪一個數字,都會碰到一個滿足i % j == 0
的狀況,也就是當i == j
的時候。所以如果真的要把int(i ** 0.5)
改成int(i)
的話,改成如下就能正常執行:
def find_prime(end, start=2):
prime_list = []
for i in range(start, end+1):
j = 1
while j < int(i - 1):
j += 1
if i % j == 0:
break
else:
prime_list.append(i)
return prime_list
find_prime(100)
[2,
3,
5,
7,
11,
13,
17,
19,
23,
29,
31,
37,
41,
43,
47,
53,
59,
61,
67,
71,
73,
79,
83,
89,
97]
檢查質數的程式碼,因為涉及到迴圈以及條件判斷式,思考起來可能比較複雜。也許可以試著把i
、j
一個數字一個數字帶進去模擬迴圈運作的情形,也許對於程式碼執行的狀況會有多一點感覺。
我還在消化中,但想先謝謝您詳盡且耐心的解說~!