iT邦幫忙

第 11 屆 iThome 鐵人賽

DAY 6
1
Modern Web

從LINE BOT到資料視覺化:賴田捕手系列 第 6

第 06 天:Python:常用句型

  • 分享至 

  • xImage
  •  

第 06 天:Python:常用句型

但突然間我改變了心意。突然間,我決定我真正該做的是什麼。我差不多該要離開這個迴圈了,就在今天晚上。

~節錄自《賴田捕手》第七章

  經過前兩天的努力,我們已經學會 Python 中基本的,也是最常用的資料結構,包括清單(list)、不可變更清單(tuple)、字典(dict)、集合(set)。我想要講,卻還未能講清楚的物件,就只剩下函數(function)了。在 Python 中,函數就像是一篇文章,或是一個小品。你寫出一段又一段的程式碼,把它們用函數包裝起來,賦予它們機動性。讓你可以輕鬆的把它們塞進口袋,帶著它們環遊世界。好比說,在 101 閃耀的 LED 燈光照射下,靠著陽台,拿出來好好品味一番。
  要寫出優美動人的文章,除了要有一顆多愁善感的心,還必須有打磨過後洗鍊的表達技巧才行。也就是說,我們要熟悉撰寫文章的語法。那麼就先來講講 Python 當中常用的幾種句型吧!

如果,不然(ifelifelse)

  第一個要介紹的句型是如果,不然。如果大家還受得了的話,我就繼續來分享我家草泥馬的生活點滴囉!不然,我來講些比較學術性的東西好了。
  草泥馬其實是很有求知慾的生物。我住的地方累積了不少以前上學時,學校發下來的課本或老師發的講義,書架上、床底下、衣櫃裡,堆得滿滿滿。有一次在整理裝箱的時候,正巧被草泥馬看到。那隻草泥馬,當時因為腸胃不適的關係,總是沒什麼精神。結果意想不到的事情發生了。就著零零落落散落一地的教科書,牠居然乖乖盤腿坐下,聚精會神,一本一本地啃了起來。啃,就是字面上的意思,嚼食。原來教科書非常幫助消化啊!
  從此以後,教科書就成了草泥馬們最愛的零嘴。牠們尤其喜歡數學相關的教科書。原本我有滿滿一整架書櫃的數學課本、參考書、講義、習題、考卷,被牠們每天大嚼特嚼,大概只剩下不到一成了。糟糕,總不能叫我回去當學生再收集一些數學課本吧?因此我試著讓牠們珍惜數學課本,嘗試讓牠們了解到數學課本是拿來讀的,不是拿來啃的,希望可以讓牠們戒掉這個奇怪的嗜好。效果出奇的好。我從加法開始教起,教到減法、乘法、除法,牠們已經開始有一點基本的數學概念了。最近在學的是質數。所謂的質數,就是除了 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的程式碼。然後,在ifelif都回傳False的情況下,執行附屬於else的程式碼。
  最後兩行,因為沒有使用縮排,不附屬於任何一種情況,所以不管上面執行了哪一段程式碼,在做完ifelifelse等等的判斷之後,都會被執行。不管如何,日子總要繼續過下去的!

  這邊講一下判斷句使用的運算符號。還記得一開始的number % 2 == 0嗎?為什麼不是用number % 2 = 0呢?因為只用=,是貼標籤的意思,硬要這樣寫的話,就會變成:「把number % 2這個標籤貼在整數物件0上」。當然是錯誤的用法。為了區隔數學上的等號,跟 Python 中的貼標籤,在 Python 中,等於會表示為==表一列出了常用的判斷句運算符號。

表一、常用的判斷句運算符號

運算 運算子
等於 ==
不等於 !=
小於 <
大於 >
小於等於 <=
大於等於 >=
在...之中 in

當(while)

  第二個要介紹的句型是。當(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 相當聰明,他知道接在ifelif、或是while後面的判斷語句,需要負責回傳TrueFalse,因此自動把這些物件都布林化了。所以寫成 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:
      聊天超過 15 次已經充分表現出蔑視的態度了。
  • 第七行: print('==無用學習==')
      再繼續下去也不會有草泥馬從中學到知識。
  • 第八行: break
      不管我的合作夥伴是否還有耐心,我直接宣布課程終止。

  這邊我們用到了一個新東西break。在while迴圈,或是等等會介紹到的for迴圈裡,碰到break,不管三七二十一,就是會終止這個迴圈的運作。
  另外還有個有趣但不太直覺的東西。Python有ifelse這種句型組合,也有whileelse這種句型組合。whileelse裡面的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)是今天會學到的最後一個句型。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中有哪些物件呢?我們知道有三個物件,分別是235。用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紀錄當下ni的值。
  • 第五行: 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):
      就不再講第一行跟第三行了。同時,因為這次我們拿了 Python的計數器來用,所以原本手動的n = 1計數器也可以不用了。先來翻譯一下:「對於在enumerate(prime_list, 1)中的ni」。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的程式碼,跑一次迴圈。
      這次的程式碼只有 3 行,卻做到了跟上面 5 行程式碼一樣的效果。手指的疲勞得到了舒緩,謝謝 Python!

  既然提到了手指的疲勞,就不能不說一下分憂解勞、居家必備的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)。怎麼樣,夠紓壓了吧?
      不過看看 Python 運行的結果,恩,好像哪裡還不夠完美呢。我們想要把從 1 到 10 之間,不是質數的數字都列出來,0 跟 1 雖然不是質數,但他們處在一個比較尷尬的位置,我不希望把他們列出來。那換個方式,從二開始數就不會有問題了吧:
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 聊天機器人。加油吧大家!今天的用到的程式碼在這(Githubnbviewer)。大家也可以參考 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 按鈕


上一篇
第 05 天:Python:資料結構與基本操作(二)
下一篇
第 07 天:Python:函數物件
系列文
從LINE BOT到資料視覺化:賴田捕手30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

1 則留言

0
tsz
iT邦新手 5 級 ‧ 2021-07-30 16:51:07

您好,我剛開始學習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

這個程式碼當中,ij都是 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就是i0.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迴圈,會讓i0一直數到4。然而我們在迴圈當中加入break,當滿足條件i == 2break執行,整個迴圈就嘎然而止了。那麼什麼叫做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-elsebreak驗證機制。同理,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]

檢查質數的程式碼,因為涉及到迴圈以及條件判斷式,思考起來可能比較複雜。也許可以試著把ij一個數字一個數字帶進去模擬迴圈運作的情形,也許對於程式碼執行的狀況會有多一點感覺。

tsz iT邦新手 5 級 ‧ 2021-08-04 17:10:44 檢舉

我還在消化中,但想先謝謝您詳盡且耐心的解說~!

我要留言

立即登入留言