Python for 迴圈是用來對序列(List、字串、Tuple、Dict 等)或數字範圍進行逐一迭代的語法,搭配內建函數 range() 可以精確控制迴圈次數與步進方式。本文完整解析 for 迴圈的基本語法、range() 的三種用法、enumerate() 與 zip() 的進階迭代技巧、break 與 continue 控制流程,以及量化回測中逐根 K 線處理的實戰應用。
什麼是 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 序列:是固定語法結構。冒號後的縮排區塊會對序列中每一個元素執行一次,縮排結束即代表迴圈結束。變數名稱可以自訂,慣例使用有意義的單數名詞(如item、fruit、row)。
# === 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,一行搞定,效能也更好。