Python for 迴圈:序列迭代與 range() 實戰

Python for 迴圈是用來對序列(List、字串、Tuple、Dict 等)或數字範圍進行逐一迭代的語法,搭配內建函數 range() 可以精確控制迴圈次數與步進方式。本文完整解析 for 迴圈的基本語法、range() 的三種用法、enumerate()zip() 的進階迭代技巧、breakcontinue 控制流程,以及量化回測中逐根 K 線處理的實戰應用。

Cinematic dark alchemy forge with a glowing circular conveyor of amber light orbs passing through a mystical processing gate one by one, representing Python for loop iteration, deep shadows on ancient stone walls, dramatic cinematic lighting, 16:9

什麼是 for 迴圈?

for 迴圈是 Python 中最常用的重複執行語法,它會依序從序列中取出每一個元素,並對每個元素執行相同的程式碼區塊,直到所有元素都處理完畢為止。與 while 迴圈相比,for 迴圈的迭代次數通常是明確已知的,適合用在「對集合裡的每一項做同樣處理」的場景。

可以把 for 迴圈想像成流水線上的自動機械臂:傳送帶把物品一個個送過來,機械臂對每一個物品執行同樣的動作,直到傳送帶清空。range() 則是製造「指定數量空箱子」的機器,讓你控制傳送帶要轉幾圈。

核心語法:for 與 range() 實戰

# === 基本 for 迴圈:迭代 List ===
fruits = ['apple', 'banana', 'orange', 'mango']

for fruit in fruits:           # 每次從 fruits 取出一個元素存到 fruit
    print(f"水果:{fruit}")

# 輸出:
# 水果:apple
# 水果:banana
# 水果:orange
# 水果:mango

# === 迭代字串(字串也是序列)===
for char in "Python":
    print(char, end=' ')    # end=' ' 讓輸出在同一行
# 輸出:P y t h o n
for 變數 in 序列: 是固定語法結構。冒號後的縮排區塊會對序列中每一個元素執行一次,縮排結束即代表迴圈結束。變數名稱可以自訂,慣例使用有意義的單數名詞(如 itemfruitrow)。
# === range():產生數字序列 ===

# range(stop):從 0 開始,到 stop-1 結束
for i in range(5):
    print(i, end=' ')    # 0 1 2 3 4

print()   # 換行

# range(start, stop):從 start 開始,到 stop-1 結束
for i in range(2, 8):
    print(i, end=' ')    # 2 3 4 5 6 7

print()

# range(start, stop, step):指定步進值
for i in range(0, 20, 5):
    print(i, end=' ')    # 0 5 10 15

print()

# 倒數:step 為負數
for i in range(10, 0, -2):
    print(i, end=' ')    # 10 8 6 4 2

print()

# 常見用法:執行固定次數
for _ in range(3):       # _ 表示不需要用到迴圈變數
    print("重複執行")
range() 不會真的建立一個完整的 List,而是產生一個惰性(lazy)的迭代物件,在需要時才逐一產生數字,因此即使 range(1_000_000) 也不會消耗大量記憶體。若需要轉為 List,使用 list(range(5))

規則與注意事項

規則 正確範例 錯誤範例 / 陷阱
for 行尾必須有冒號 for i in range(5): for i in range(5) → SyntaxError
迴圈區塊必須縮排 縮排 4 空格的程式碼屬於迴圈內 無縮排 → IndentationError
range(stop) 不包含 stop 本身 range(5) → 0,1,2,3,4(共 5 個) 誤以為 range(5) 包含 5
不要在迴圈內修改正在迭代的 List 迭代副本:for x in my_list[:]: 邊迭代邊刪除元素 → 跳過元素或行為異常
不需要用到索引時,用 _ 作為變數名 for _ in range(3): i 但從不使用 → 程式碼不夠清晰

常見錯誤與防呆

錯誤一:range() 的 stop 不含邊界,差一錯誤(Off-by-one)

# ❌ 錯誤觀念(想印 1 到 10,但 range(10) 只到 9)
for i in range(10):
    print(i, end=' ')   # 0 1 2 3 4 5 6 7 8 9(沒有 10!)

# ✅ 正確寫法:想包含 10,stop 要寫 11
for i in range(1, 11):
    print(i, end=' ')   # 1 2 3 4 5 6 7 8 9 10

錯誤二:迴圈內修改正在迭代的 List

# ❌ 錯誤寫法(邊迭代邊刪除,會跳過元素)
nums = [1, 2, 3, 4, 5]
for n in nums:
    if n % 2 == 0:
        nums.remove(n)   # 刪除偶數,但會跳過某些元素
print(nums)   # [1, 3, 5] ← 看似正確,但某些情況會出錯

# ✅ 正確做法:迭代副本,或用 List Comprehension 重建
nums = [1, 2, 3, 4, 5]
nums = [n for n in nums if n % 2 != 0]
print(nums)   # [1, 3, 5]

錯誤三:誤以為 for 迴圈結束後迴圈變數消失

# Python 的 for 迴圈變數在迴圈結束後仍然存在
for i in range(5):
    pass

print(i)   # 4(迴圈結束後 i 保留最後一個值)

# ✅ 若不想讓迴圈變數污染外部作用域,可在迴圈後明確刪除
del i

進階用法

enumerate():同時取索引與值

當迭代時需要同時知道元素的索引位置與值,使用 enumerate() 比手動維護計數器更簡潔安全。

tickers = ['AAPL', 'TSLA', 'GOOGL', 'MSFT']

# 一般做法(不推薦)
for i in range(len(tickers)):
    print(f"{i}: {tickers[i]}")

# ✅ 推薦:enumerate() 同時取索引與值
for i, ticker in enumerate(tickers):
    print(f"{i}: {ticker}")
# 0: AAPL
# 1: TSLA
# 2: GOOGL
# 3: MSFT

# 可指定起始索引(預設為 0)
for i, ticker in enumerate(tickers, start=1):
    print(f"第 {i} 檔:{ticker}")
# 第 1 檔:AAPL ...

zip():同時迭代多個序列

zip() 可以將兩個或多個序列配對打包同步迭代,適合需要對應處理多組資料的場景,例如同時走訪日期與收盤價。

dates  = ['2024-01-02', '2024-01-03', '2024-01-04']
closes = [185.2, 187.8, 183.5]
volumes = [45000000, 52000000, 38000000]

# zip() 同時迭代三個 List
for date, close, vol in zip(dates, closes, volumes):
    print(f"{date}  收盤:{close}  成交量:{vol:,}")
# 2024-01-02  收盤:185.2  成交量:45,000,000
# 2024-01-03  收盤:187.8  成交量:52,000,000
# 2024-01-04  收盤:183.5  成交量:38,000,000

break 與 continue:控制迴圈流程

break 用來立即跳出整個迴圈continue 用來跳過當前這一次迭代,直接進入下一次。兩者都常用於在迴圈中加入條件篩選或提前終止邏輯。

closes = [102.5, 108.3, 95.0, 113.7, 88.5, 121.0]

# continue:跳過收盤價低於 100 的 K 線
print("有效收盤價(>= 100):")
for c in closes:
    if c < 100:
        continue          # 跳過這次,繼續下一個
    print(f"  {c}")
# 102.5, 108.3, 113.7, 121.0

# break:找到第一根收盤超過 110 的 K 線後停止
print("\n首次突破 110:")
for i, c in enumerate(closes):
    if c > 110:
        print(f"  第 {i} 根 K 線,收盤:{c}")
        break             # 找到後立即停止迴圈
# 第 3 根 K 線,收盤:113.7

煉金坊小叮嚀

for 迴圈是我在量化開發中使用頻率最高的語法——逐根 K 線計算指標、批次跑回測參數、整理歷史資料,全都離不開它。有幾個習慣我強烈建議從一開始就養成:需要索引時用 enumerate(),不要再用 range(len(...)),前者更安全也更 Pythonic。另外,range() 的 stop 不含邊界這件事請牢記,差一錯誤(Off-by-one)是迴圈中最常見的 bug,通常不會報錯,只會讓結果悄悄少一筆或多一筆。如果迴圈只是把 List 的每個元素轉換後收集成新 List,優先考慮第 18 篇的 List Comprehension,一行搞定,效能也更好。

張貼留言

較新的 較舊