消除迴圈

撰寫高效的 Python 程式碼

Logan Thomas

Scientific Software Technical Trainer, Enthought

Python 的迴圈

  • 迴圈樣式:
    • for 迴圈:逐一走訪序列
    • while 迴圈:條件成立就重複
    • 「巢狀」迴圈:在迴圈裡再用迴圈
    • 成本高!
撰寫高效的 Python 程式碼

消除迴圈的好處

  • 程式碼更精簡
  • 可讀性更好
    • 「扁平勝於巢狀」
  • 效率提升
撰寫高效的 Python 程式碼

用內建功能消除迴圈

# List of HP, Attack, Defense, Speed
poke_stats = [
    [90,  92, 75, 60],
    [25,  20, 15, 90],
    [65, 130, 60, 75],
    ...
]

替代文字:顯示寶可夢 Abomasnow、Abra、Absol,以及其對應的體力、攻擊、防禦、速度等欄位已標示

撰寫高效的 Python 程式碼
# List of HP, Attack, Defense, Speed
poke_stats = [
    [90,  92, 75, 60],
    [25,  20, 15, 90],
    [65, 130, 60, 75],
    ...
]

# For 迴圈作法 totals = [] for row in poke_stats: totals.append(sum(row))
# 串列生成式 totals_comp = [sum(row) for row in poke_stats]
# 內建 map() 函式 totals_map = [*map(sum, poke_stats)]
撰寫高效的 Python 程式碼
%%timeit
totals = []
for row in poke_stats:
    totals.append(sum(row))
每回圈 140 µs ± 1.94 µs(7 次、各 10000 回圈;平均值 ± 標準差)
%timeit totals_comp = [sum(row) for row in poke_stats]
每回圈 114 µs ± 3.55 µs(7 次、各 10000 回圈;平均值 ± 標準差)
%timeit totals_map = [*map(sum, poke_stats)]
每回圈 95 µs ± 2.94 µs(7 次、各 10000 回圈;平均值 ± 標準差)
撰寫高效的 Python 程式碼

用內建模組消除迴圈

poke_types = ['Bug', 'Fire', 'Ghost', 'Grass', 'Water']
# 巢狀 for 迴圈作法
combos = []
for x in poke_types:
    for y in poke_types:
        if x == y:
            continue
        if ((x,y) not in combos) & ((y,x) not in combos):
            combos.append((x,y))
# 內建模組作法
from itertools import combinations
combos2 = [*combinations(poke_types, 2)]
撰寫高效的 Python 程式碼

用 NumPy 消除迴圈

# Array of HP, Attack, Defense, Speed
import numpy as np

poke_stats = np.array([
    [90,  92, 75, 60],
    [25,  20, 15, 90],
    [65, 130, 60, 75],
    ...
])
撰寫高效的 Python 程式碼

用 NumPy 消除迴圈

avgs = []
for row in poke_stats:
    avg = np.mean(row)
    avgs.append(avg)

print(avgs)
[79.25, 37.5, 82.5, ...]
avgs_np = poke_stats.mean(axis=1)

print(avgs_np)
[ 79.25  37.5   82.5  ...]
撰寫高效的 Python 程式碼

用 NumPy 消除迴圈

%timeit avgs = poke_stats.mean(axis=1)
每回圈 23.1 µs ± 235 ns(7 次、各 10000 回圈;平均值 ± 標準差)
%%timeit
avgs = []
for row in poke_stats:
    avg = np.mean(row)
    avgs.append(avg)
每回圈 5.54 ms ± 224 µs(7 次、各 100 回圈;平均值 ± 標準差)
撰寫高效的 Python 程式碼

一起來練習吧!

撰寫高效的 Python 程式碼

Preparing Video For Download...