Python 迴圈控制 (08):用 break/continue、巢狀迴圈與列表推導式寫出俐落程式

當資料一多、條件一複雜,單純的 forwhile 很快就顯得笨重:找到就應該馬上停、不符合就跳過、二維資料需要巢狀走訪,還想把「過濾+轉換」濃縮成一行可讀的寫法

本篇帶你把迴圈升級成「可控又優雅」的工具:學會 breakcontinue 的正確時機、避開無限迴圈的陷阱、處理巢狀結構,最後用列表推導式(含條件)把常見的資料處理寫得又短又清楚。

Python break statement flowchart showing exit loop completely

迴圈控制:Break

Python中的迴圈非常靈活。Python提供了一組控制語句,我們可以使用它們來獲得對迴圈的更多控制。

讓我們看一個常見的場景,以了解迴圈控制語句的用例。

場景

items_on_sale = ["blue shirt", 
"striped socks", "knit dress", 
"red headband", "dinosaur onesie"]

我們經常需要搜索列表以檢查特定值是否存在。如果我們想搜索”knit dress”的值並在它存在時打印出”找到了”,我們的迴圈會是什麼樣子?

for item in items_on_sale:
    if item == "knit dress":
        print("找到了")

問題

一旦在items_on_sale列表中找到”knit_dress”,我們就不需要繼續遍歷items_on_sale列表的其餘部分。不幸的是,我們的迴圈將繼續運行,直到我們到達列表的末尾。

對於只有5個元素的列表來說,迭代整個列表不是大問題,但如果items_on_sale有1000個項目呢?如果它有100,000個項目呢?這對我們的程序來說將是巨大的時間浪費!

幸運的是,您可以使用break迴圈控制語句從迴圈內部停止迭代。當程序遇到break語句時,它會立即終止迴圈。例如:

items_on_sale = ["blue shirt", "striped socks", "knit dress", "red headband", "dinosaur onesie"]
print("檢查銷售列表!")
for item in items_on_sale:
    print(item)
    if item == "knit dress":
        break
print("搜索結束!")

這將產生輸出:

檢查銷售列表!
blue shirt
striped socks
knit dress
搜索結束!

當迴圈進入if語句並看到break時,它立即結束了迴圈。我們根本不需要檢查”red headband”或”dinosaur onesie”的元素。

Python continue statement flowchart showing skip current iteration

迴圈控制:Continue

雖然break控制語句會派上用場,但還有其他情況我們不想完全結束迴圈。如果我們只想跳過迴圈的當前迭代怎麼辦?

讓我們以這個整數列表為例:

big_number_list = [1, 2, -1, 4, -5, 5, 2, -9]

如果我們想打印列表中的所有數字,但前提是它們是正整數,我們可以使用另一個常見的迴圈控制語句continue

使用continue

for i in big_number_list:
    if i <= 0:
        continue
    print(i)

這將產生輸出:

1
2
4
5
2

運作原理

  1. 與使用break控制語句時類似,我們的continue控制語句通常與某種形式的條件(if/elif/else)配對。
  2. 當我們的迴圈第一次遇到滿足if語句條件的元素(1)時,它檢查塊內的代碼並看到continue。當迴圈遇到continue語句時,它立即跳過當前迭代並移到列表中的下一個元素(4)。
  3. 列表的輸出只打印了列表中的正整數,因為每次我們的迴圈進入if語句並看到continue語句時,它只是移到列表的下一次迭代,因此永遠不會到達print語句

無限迴圈

我們已經迭代了具有明確開始和結束的列表。但是,讓我們考慮以下示例:

my_favorite_numbers = [4, 8, 15, 16, 42]
for number in my_favorite_numbers:
    my_favorite_numbers.append(1)

思考一下這段代碼會發生什麼。

每次我們進入迴圈,我們在我們正在迭代的列表末尾添加一個1。結果,我們永遠不會到達列表的末尾。它會無限增長!

無限迴圈的危險

  • 永不終止的迴圈稱為無限迴圈
  • 這對我們的代碼非常危險
  • 會使程序運行永遠並消耗所有計算機資源
  • 進入無限迴圈的程序通常變得完全無法使用

處理無限迴圈

  • 最好的做法是避免編寫無限迴圈
  • 確保迴圈有明確的結束條件
  • 如果不小心進入無限迴圈:
    • 在自己的機器上開發時,可以使用control + c終止程序
    • 在在線編輯器中編寫代碼時,需要刷新頁面以退出無限迴圈

巢狀迴圈

與其他程式設計語言一樣,Python中的迴圈可以巢狀。我們會發現某些情況需要巢狀迴圈。

假設我們負責一個科學課,該課程分為三個項目團隊:

project_teams = [["Ava", "Samantha", "James"], ["Lucille", "Zed"], ["Edgar", "Gabriel"]]

獲取每個團隊

for team in project_teams:
    print(team)

輸出:

["Ava", "Samantha", "James"]
["Lucille", "Zed"]
["Edgar", "Gabriel"]

獲取每個學生

如果我們想打印每個單獨的學生呢?在這種情況下,我們實際上需要巢狀我們的迴圈以能夠遍歷每個子列表。以下是它的樣子:

# 遍歷每個子列表
for team in project_teams:
    # 遍歷每個子列表中的元素
    for student in team:
        print(student)

輸出:

Ava
Samantha
James
Lucille
Zed
Edgar
Gabriel
Python list comprehension syntax diagrams with if and if-else conditions

列表推導式:基本介紹

到目前為止,我們已經看到了在代碼中使用迴圈的許多想法。Python以允許程式設計師編寫乾淨優雅的代碼而自豪。我們已經看到Python讓我們能夠在一行中編寫while和for迴圈。

在本節中,我們將使用列表推導式來檢查另一種在程序中編寫優雅迴圈的方式。

傳統方法

假設我們有一個整數列表,並想創建一個每個元素都翻倍的列表。我們可以使用for迴圈和一個名為doubled的新列表來完成這個任務:

numbers = [2, -1, 79, 33, -45]
doubled = []
for number in numbers:
    doubled.append(number * 2)
print(doubled)

輸出:

[4, -2, 158, 66, -90]

列表推導式方法

讓我們看看如何使用列表推導式的力量來在一行中解決這些類型的問題。以下是我們相同的問題,但現在用列表推導式編寫:

numbers = [2, -1, 79, 33, -45]
doubled = [num * 2 for num in numbers]
print(doubled)

輸出:

[4, -2, 158, 66, -90]

讓我們以更一般的方式分解我們的示例:

new_list = [<表達式> for <元素> in <集合>]

在我們的doubled示例中,我們的列表推導式:

  1. 取numbers列表中的一個元素
  2. 將該元素分配給一個名為num的變數(我們的<元素>)
  3. 對存儲在num中的元素應用<表達式>,並將結果添加到一個名為doubled的新列表中
  4. 對numbers列表(我們的<集合>)中的每個其他元素重複步驟1-3

列表推導式:條件

列表推導式非常靈活。我們甚至可以擴展我們的示例以包含條件邏輯。

假設我們只想將之前numbers列表中的負數翻倍。

傳統方法

我們將使用for迴圈和一個名為only_negative_doubled的列表:

numbers = [2, -1, 79, 33, -45]
only_negative_doubled = []
for num in numbers:
    if num < 0:
        only_negative_doubled.append(num * 2)
print(only_negative_doubled)

輸出:

[-2, -90]

列表推導式方法

現在,以下是使用列表推導式的代碼:

numbers = [2, -1, 79, 33, -45]
negative_doubled = [num * 2 
                   for num in numbers 
                   if num < 0]
print(negative_doubled)

輸出同樣的結果:

[-2, -90]

帶條件的列表推導式運作原理

  1. 取numbers列表中的一個元素。
  2. 將該元素分配給一個名為num的變數。
  3. 檢查num < 0條件是否被存儲在num中的元素滿足。如果是,它會進入步驟4,否則它會跳過並進入列表中的下一個元素。
  4. 對存儲在num中的元素應用表達式num * 2,並將結果添加到一個名為negative_doubled的新列表中。
  5. 對numbers列表中的每個剩餘元素重複步驟1-3(有時是4)。

迴圈實例:數據過濾

讓我們通過一個實際例子來應用我們學到的迴圈知識:過濾學生成績數據。

student_scores = [
    {"name": "張三", "score": 95},
    {"name": "李四", "score": 65},
    {"name": "王五", "score": 88},
    {"name": "趙六", "score": 72},
    {"name": "錢七", "score": 91}
]

使用For迴圈過濾

high_scorers = []
for student in student_scores:
    if student["score"] >= 90:
        high_scorers.append(student["name"])

print("優秀學生名單:")
for name in high_scorers:
    print(name)

輸出:

優秀學生名單:
張三
錢七

使用列表推導式過濾

high_scorers = [student["name"] 
               for student in student_scores 
               if student["score"] >= 90]

print("優秀學生名單:")
print("\n".join(high_scorers))

輸出:

優秀學生名單:
張三
錢七

列表推導式讓我們能夠用一行代碼完成相同的過濾操作,使代碼更簡潔、更易讀。

這個例子展示了如何使用迴圈和列表推導式來處理真實世界的數據過濾需求。無論是傳統的for迴圈還是更簡潔的列表推導式,兩種方法都能有效地完成任務。選擇哪種方法取決於代碼的可讀性和團隊的編碼風格偏好。

發佈留言

發佈留言必須填寫的電子郵件地址不會公開。 必填欄位標示為 *

返回頂端