本文 AI 產出,尚未審核

Python 課程 – 運算子(Operators)

主題:運算子優先順序


簡介

在寫程式時,我們常會把多個運算子組合在同一行,例如 a + b * c - d / e。如果不清楚 運算子優先順序(operator precedence),程式的執行結果可能會與預期大相逕庭,甚至產生難以偵測的錯誤。

了解 Python 的優先順序不只是為了「算對」;它還能幫助我們寫出 易讀、易維護 的程式碼。透過正確的運算子排列與適度的括號使用,我們可以減少程式的歧義,讓團隊成員在閱讀時一眼就能看懂邏輯。

本篇文章將從概念說明、實作範例、常見陷阱與最佳實踐,逐步帶領讀者掌握 Python 運算子的優先順序,並提供實務上常見的應用情境。


核心概念

Python 的運算子優先順序遵循一套固定的規則,從「最高」到「最低」依序排列。以下是最常見的幾大類別(省略了少數較特殊的運算子):

優先順序 類別 代表運算子 說明
1 指數 ** 右結合(ex: 2 ** 3 ** 22 ** (3 ** 2)
2 正負號、位元反相 +x, -x, ~x 單目運算子
3 乘除取餘 *, /, //, % 左結合
4 加減 +, - 左結合
5 位元移位 <<, >> 左結合
6 位元與 & 左結合
7 位元異或 ^ 左結合
8 位元或 ` `
9 比較 ==, !=, <, >, <=, >=, is, is not, in, not in 左結合,且可鏈接(ex: a < b < c
10 布林 NOT not 單目
11 布林 AND and 左結合
12 布林 OR or 左結合
13 條件運算子 if … else 右結合
14 賦值與增減 =, +=, -= 右結合

小技巧:若不確定優先順序,最安全的做法是加上括號,讓意圖一目了然。

1. 右結合 vs. 左結合

  • 左結合:從左至右依序計算。
    result = 2 - 3 + 4   # 先算 (2 - 3) 再加 4 → 3
    
  • 右結合:從右至左計算。
    result = 2 ** 3 ** 2   # 先算 (3 ** 2) 再算 2 ** 9 → 512
    

2. 為什麼 Python 把比較運算子放在同一層?

Python 允許 鏈式比較,如 a < b <= c,等同於 a < b and b <= c。這在寫區間判斷時特別方便。


程式碼範例

以下示範 5 個常見情境,說明優先順序如何影響結果。每段程式碼皆附有註解,方便閱讀。

範例 1:指數與乘除的結合

# 先算指數,再算乘除
a = 2 ** 3 * 4      # 等同於 (2 ** 3) * 4 → 8 * 4 = 32
b = 2 ** (3 * 4)    # 括號改變順序 → 2 ** 12 = 4096
print(a, b)         # 輸出:32 4096

重點** 的優先順序高於 *,若希望先乘再指數,必須自行加上括號。

範例 2:位元運算與布林運算的混合

x = 0b1100          # 十進位 12
y = 0b1010          # 十進位 10

# 位元 AND 先於布林 OR
result = x & y == 0b1000 or x | y == 0b1110
# 先算 (x & y) == 0b1000 → (0b1000 == 0b1000) → True
# 再算 x | y == 0b1110 → (0b1110 == 0b1110) → True
# 最後 True or True → True
print(result)       # 輸出:True

提醒:比較運算子 (==) 的優先順序高於位元運算子 (&, |)。

範例 3:鏈式比較與邏輯 NOT

a = 5
b = 10
c = 15

# 鏈式比較自動加入 AND
cond = a < b < c and not (b == 10)
# a < b < c  → True
# b == 10   → True → not True = False
# 最終 cond = True and False → False
print(cond)         # 輸出:False

技巧:利用鏈式比較可以省去多餘的 and,但仍要注意 not 的優先順序,它在比較之後才生效。

範例 4:條件運算子(三元運算子)

score = 78

# 條件運算子優先順序最低,通常放在最外層
grade = "A" if score >= 90 else "B" if score >= 80 else "C"
print(grade)        # 輸出:C

說明:條件運算子是右結合的,寫多層時要特別留意縮排與可讀性,必要時可改寫成完整的 if/elif/else 結構。

範例 5:賦值運算子與算術運算的結合

x = 10
x += 5 * 2          # 等同於 x = x + (5 * 2) → x = 10 + 10 → 20
print(x)            # 輸出:20

# 若不加括號,會產生 SyntaxError
# x =+ 5 * 2   # 錯誤寫法,會被解析成 x = (+5) * 2

注意:賦值運算子 (+=, -= …) 的優先順序最低,左側變數永遠先被評估。


常見陷阱與最佳實踐

陷阱 可能的錯誤 建議的寫法
忘記加括號 2 ** 3 ** 2 產生 512,而非預期的 64 使用 (2 ** 3) ** 2 或明確說明需求
位元與比較混用 a & b == c 會先比較 b == c 再與 a 做位元 AND,結果常出乎意料 改寫為 (a & b) == c
not 與比較的優先順序 not a == b 變成 not (a == b),但有時想要 (not a) == b 用括號明確 (not a) == b
鏈式比較的誤用 a < b > c 其實等同於 a < b and b > c,若忘記 b 必須同時滿足兩條件,容易寫錯 寫成 a < b and b > c,或在註解說明意圖
條件運算子過長 x = a if cond1 else b if cond2 else c if cond3 else d 可讀性極差 改寫為多行 if/elif/else,或使用函式封裝

最佳實踐

  1. 優先使用括號:即使 Python 已有明確的優先順序,加入括號可以讓程式碼自說自話
  2. 保持左至右的閱讀流程:盡量讓運算子出現在同一層級,避免跨層級的混合(例如同一行同時出現 +and==)。
  3. 使用 is 判斷單例:比較 NoneTrueFalse 時,請用 is 而非 ==,因為 is 的優先順序比比較運算子更高,能避免意外的類別相等判斷。
  4. 在條件式內避免副作用:例如 x = func() and y = other() 會因為 and 的短路機制產生不易預期的執行順序,建議分開寫。

實際應用場景

1. 數據分析 – 篩選條件的組合

import pandas as pd

df = pd.DataFrame({
    "age": [22, 35, 27, 45],
    "salary": [35000, 80000, 56000, 120000],
    "dept": ["HR", "IT", "IT", "Finance"]
})

# 篩選條件:年齡 > 30 且 (薪資 > 70000 或 部門為 IT)
cond = (df["age"] > 30) & ((df["salary"] > 70000) | (df["dept"] == "IT"))
result = df[cond]
print(result)

這裡使用了 位元與 (&)位元或 (|)比較 的混合,必須在每個子條件外加括號,否則會因優先順序錯誤而拋出 ValueError

2. 網站開發 – 權限驗證

def has_access(user, resource):
    # 只有 admin 或 (owner 且 resource 為公開) 才可存取
    return user.is_admin or (user.is_owner(resource) and resource.is_public)

# 呼叫時,條件運算子優先順序保證先算 and,再算 or

3. 演算法 – 貪婪選擇

def greedy_knapsack(items, capacity):
    # items 為 (weight, value) 的 tuple
    items.sort(key=lambda x: x[1] / x[0], reverse=True)   # 依價值密度遞減排序
    total_value = 0
    for w, v in items:
        if capacity >= w:
            capacity -= w
            total_value += v
        else:
            total_value += v * capacity / w   # 部分填充
            break
    return total_value

if capacity >= w: 中,比較運算子優先於賦值 (-=+=),不需要額外括號。


總結

  • Python 的運算子優先順序從指數 (**) 到賦值 (=) 分為 14 層,掌握這個順序即可避免大多數的運算錯誤。
  • 右結合左結合的概念決定了同一層級運算子在同一表達式中的計算方向。
  • 在實務開發中,加括號分段寫條件避免混用位元與比較 是提升程式可讀性與除錯效率的關鍵。
  • 透過本篇的範例與最佳實踐,你應該能在資料分析、網站開發、演算法實作等情境下,正確運用運算子優先順序,寫出 清晰、可靠 的 Python 程式碼。

記住:程式的可讀性永遠比「省一行」更重要,而運算子優先順序正是提升可讀性的基石。祝你寫程式愉快!