P04 Flow Control#

for-if-else的語法概念本身並不難,一個是重複執行的結構,一個是條件判斷式。學習重點應在於,怎麼活用他們來完成一些任務。

  • for-loo-: Interating and Traversing

    • 基本用法:用於計數和列出特定資料集。

    • 列舉(Iterating):遍歷列表或其他集合型態的所有元素。

    • 走訪(Traversing):用於走訪複雜的資料結構,如多維陣列或樹狀結構。

  • break 和 continue:控制迴圈

    • continue:在特定條件下跳過迴圈內剩餘的指令。

    • break:在特定條件下終止整個迴圈。

    • 在網路爬蟲中常用,以處理不確定的爬取範圍和資料可用性。

  • range() 函式

    • 用於生成數字序列。

    • 可接受一個、兩個或三個參數,以控制數字序列的起始、結束和間隔。

    • 可用於逆序列舉和資料型態轉換。

  • Nested for-loop

    • 基本語法:一個迴圈內包含另一個或多個迴圈。

    • 應用場景:二維數組遍歷、矩陣運算等。

    • 計算量較大,需注意效能問題。

    • 實作:九九乘法表實作

  • if-elif-else

    • 應用場景:多條件判斷、多分支判斷、多路徑判斷

    • 實作:成績等第制

For: Traverse and Iterate#

for 是一個極為強大的程式指令,不僅可以用於計數,還能用於列出所有特定資料集(如youbike站台)的相關資訊。其基本作用是在指定的範疇或資料結構中重複執行一段程式碼,因此它也常被稱作for-each迴圈。

  • 列舉(Iterating): for 迴圈可以遍歷(iterate)一個列表(list)或其他集合型態的所有元素,並對每一個元素執行特定操作。例如,你可以用它來計算數字的總和或平均值。

  • 走訪(Traversing): 除了基本的列舉外,for 迴圈還可以用於走訪複雜的資料結構,例如多維陣列或樹狀結構。

簡而言之,這裡的 for 迴圈是一個多用途的工具,能有效地走訪或列舉列表中的每一個項目,達到如計數、排序或搜索等多種功能。

# Counting
fruit_count = {}
fruit_list = ['apple', 'apple', 'banana', 'apple', 'banana', 'grape', 'banana', 'apple']

for fruit in fruit_list:
   if fruit not in fruit_count:
       fruit_count[fruit] = 1
   else:
       fruit_count[fruit] = fruit_count[fruit] + 1

print(fruit_count)
{'apple': 4, 'banana': 3, 'grape': 1}

用以僅僅是把所有的內容給print出來。

for fruit in ['apple', 'banana', 'cherry', 'Durian']:
    print("I love", fruit)
I love apple
I love banana
I love cherry
I love Durian
table = {'Sjoerd': 41273, 'Jack': 409, 'Dcab': 7678}
for name, id in table.items():
    print(f'{name:10} ==> {id:10d}')
Sjoerd     ==>      41273
Jack       ==>        409
Dcab       ==>       7678

break & continue: 中止迴圈#

在for-loop執行過程中,有時候會希望在某些條件成立時,就直接終止並跳出整個for-loop,或者,迴圈內以下的內容就不要執行,直接執行下一個iteration。包含以下兩種指令:

  • continue: 當條件成立,下方的迴圈內容就不再執行,直接進入下一個iteration。

  • break:當條件成立,就終止整個回圈,跳出回圈的執行。

在寫爬蟲的時候經常會用到breakcontinue的指令,原因是常常不知道究竟要爬多少頁才要停下來,或者,會不會爬到一個已經被移除的貼文(例如PTT)。

  • break的應用:在撰寫爬蟲的時候,偶而會遇到不知道要爬到什麼時候,或者總資料筆數有多少(例如Twitter、DCard等等有API的服務)。此時通常會為for-loop設定一個過大停止值,例如撈個1000,000頁。此時,for-loop會一頁一頁往下撈,但總會遇到for-loop撈不到下一頁的情形,那就看看產生的錯誤是什麼,然後用if來判斷,如果出現該錯誤的時候,我就break出整個for-loop迴圈,就會停止該for-loop而不會真的撈到100,000頁。

  • continue的應用:在撰寫爬蟲的時候,通常我們會在for-loop中邊爬邊剖析資料,也就是把一個頁面爬下來之後,就立刻剖析他,偵測看看標題、作者是什麼,然後才進入下一迴圈、爬下一個頁面。但是,偶而就會遇到像是PTT的貼文一樣,明明還有該網址,但是內容卻被移除了。既然內容被移除了,那就偵測不到標題和作者了。這時候,程式的寫法往往會是,我偵測看看是不是貼文是不是被移除了,如果被移除了,雖然我把該頁抓下來了,那我就用continue跳過剖析頁面資料的過程,直接進入下一圈迴圈(沒跳過反而會出現Error)。但也許各位會問,那這樣不就和if-else很像?如果偵測到什麼,就做什麼事。但利用continue可以讓程式碼比較乾淨,不用把之後要剖析資料的程式碼,放在if-else的判斷式裡面。

continue的邏輯示意圖如下,當滿足某個條件而執行continue時,便不會執行在for-loop在continue後面的指令,而會直接進入下一圈for-loop(Illustration from https://www.geeksforgeeks.org/break-continue-and-pass-in-python/)。 image.png

grades = {'albert': 33, 'bob': 44, 'carlos': 100, 'david': 90, 'ellen': 100}
for g in grades:
    if grades[g] >=100:
        print(g)
carlos
ellen

在下面的例子中,若讀到小於100的數值,就直接進入下一個iteration,就不會執行到print(g)

grades = {'albert': 33, 'bob': 44, 'carlos': 100, 'david': 90, 'ellen': 100}
for g in grades:
    if grades[g] < 100:
        continue
    print(g)
carlos
ellen

在下面的例子中,若讀到大於等於100的數值,break會使得整個for-loop終止。通常用於找到一序列的資料中,有沒有包含某個合乎條件的情形,有的話便跳出。

grades = {'albert': 33, 'bob': 44, 'carlos': 100, 'david': 90, 'ellen': 100}
for g in grades:
    if grades[g] >= 100:
        print(g)
        break
carlos

range()函式#

range() 是一個內建函數,主要用於生成一個數字序列。這個函數可以接受一個、兩個或三個參數,各自有不同的用途。for-loop為了用index來列舉所有List中的項目,經常搭配range()使用。基本用法如下

  • 一個參數range(n) 會生成從 0n-1 的整數序列。

  • 兩個參數range(start, stop) 會生成從 startstop-1 的整數序列。

  • 三個參數range(start, stop, step) 會生成從 startstop-1 的整數序列,其中每個數字的間隔是 step

  • 逆序列舉:你可以使用負數作為 step 參數,來生成一個逆序的數字序列。如for i in range(5, 0, -1)會輸出5 4 3 2 1

  • 資料型態轉換:雖然 range() 主要用於生成整數序列,但你也可以通過轉換來創造其他類型的序列,例如將其轉換為一個列表。my_list = list(range(5))

range()函數對於for迴圈來說是極其有用的,因為他可以讓for迴圈遍歷過一個範圍內的所有數字,因而可以用來遍歷一個列表(List)或其他資料結構。

for x in range(6):
  print(x)
0
1
2
3
4
5
for x in range(2, 6):
  print(x)
2
3
4
5
for x in range(2, 30, 3):
  print(x)
2
5
8
11
14
17
20
23
26
29
alist = ['apple', 'banana', 'cherry']
for i in range(len(alist)):
    print(i, alist[i])
0 apple
1 banana
2 cherry

Nested for-loop#

在程式設計中,嵌套迴圈(nested loops)是一個迴圈內包含另一個或多個迴圈的概念。在這節教學中,我們將透過實例來介紹如何使用 Python 中的嵌套 for-loop

基本語法

for outer_var in outer_sequence:
    # outer loop body
    for inner_var in inner_sequence:
        # inner loop body
    # end of inner loop
# end of outer loop

應用情景

  • 二維數組或列表的遍歷。

  • 矩陣運算。

  • 圖形和遊戲開發中的格點系統。

補充說明

  • 嵌套迴圈會大幅度增加程式的計算量,因此,在使用時應該特別注意效能問題。適當地使用breakcontinue能夠提高嵌套迴圈的效能。


if-elif-else 條件語句教學#

在程式設計中,if-elif-else 是用來執行基於一個或多個條件的分支運算。在這節教學中,我們會透過實例來介紹如何在 Python 中使用 if-elif-else 條件語句。

基本語法

if condition1:
    # Code block for condition1
elif condition2:
    # Code block for condition2
else:
    # Code block if none of the conditions are met

範例:學生成績評定。以下是一個簡單的 if-elif-else 程式範例,用來評定學生成績。

grade = 85

if grade >= 90:
    print("優秀")
elif grade >= 80:
    print("良好")
elif grade >= 70:
    print("中等")
elif grade >= 60:
    print("及格")
else:
    print("不及格")

應用場景

  • 數值比較(例如,找出最大值或最小值)。

  • 狀態檢查(例如,檢查檔案是否存在)。

  • 資料過濾和篩選。


Example: Assign 0~100 into A, B, C, ..Class#

在這個Python練習題中,我們有一個名為grades的列表,其中包含多個學生成績(範圍為0到100分)。我們還有一個名為grade_dict的字典,用於存儲各等級(A、B、C、F)的頻率。我們的任務是使用for迴圈遍歷grades列表,並根據每個學生成績更新grade_dict字典。

  • 練習Python的基本數據結構(列表和字典)

  • 熟悉條件語句(if-elif-else

  • 練習迴圈結構

提示

  1. 條件判斷: 注意條件語句中的數字範圍。例如,等級”A”對應的分數範圍是80至100。

  2. 字典更新: 在適當的條件塊內,使用+= 1來更新grade_dict中的相應頻率。

  3. 確保範圍: 由於學生成績的範圍是0到100,所以在條件語句中確保所有可能的分數都被考慮到。

  4. 結果輸出: 最後的print(grade_dict)將顯示各等級的頻率。您可以進一步優化輸出格式,以便更易於閱讀。

# Initializing level frequency
grades = [17, 65, 5, 74, 93, 1, 94, 16, 80, 95, 32, 78, 17, 70, 22, 43, 95, 67, 3, 30, 40, 51, 96, 17, 13, 21, 4, 47, 19, 44, 59, 6, 0, 83, 40, 89, 39, 57, 99, 35, 81, 31, 89, 63, 80, 85, 36, 60, 17, 68, 62, 36, 3, 28, 8, 38, 83, 73, 67, 2]
grade_dict = {'F':0, "C":0, "B":0, "A":0}

# Counting level frequency
for g in grades:
    if 100 >= g >= 80:
        grade_dict["A"] += 1
    elif 79 >= g >= 72:
        grade_dict["B"] += 1
    elif 71 >= g >= 60:
        grade_dict["C"] += 1
    else:
        grade_dict["F"] += 1
print(grade_dict)
{'F': 35, 'C': 8, 'B': 3, 'A': 14}