Python 課程 ── 運算子(Operators)
主題:邏輯運算子(and、or、not)
簡介
在程式的流程控制裡,判斷是最常見的需求**。** 無論是條件分支、迴圈、還是資料驗證,都離不開「真假」的判斷。Python 提供的三個邏輯運算子 and、or、not,正是用來組合與翻轉布林值(True、False)的工具。
掌握這些運算子不僅能讓程式寫得更簡潔,也能避免許多隱藏的錯誤。特別是對初學者來說,了解它們的**短路求值(short‑circuit)機制與真值測試(truthiness)**概念,是寫出可靠程式的關鍵一步。
核心概念
1. 基本語意
| 運算子 | 語意說明 | 真值結果 |
|---|---|---|
and |
兩邊皆為 True 時才為 True,否則為 False | True and True → True |
or |
只要有一邊為 True 即為 True,全部為 False 時才是 False | False or True → True |
not |
把布林值反轉,True 變 False,False 變 True |
not False → True |
注意:
and、or會回傳運算結果的實際物件,而不一定是布林值本身(稍後會說明)。
2. 真值測試(Truthiness)
在 Python 中,任何物件都可以當作布林值使用。以下是常見「假」的值(Falsy):
False, None, 0, 0.0, 0j, Decimal('0'), Fraction(0, 1), '', (), [], {}, set(), range(0)
只要不是上述這些,皆被視為 True(Truthy)。因此:
>>> [] and 5 # [] 為假,直接回傳 []
[]
>>> [] or 5 # [] 為假,回傳右側 5
5
>>> not [] # [] 為假,取反為 True
True
3. 短路求值(Short‑circuit)
and 與 or 會在判斷到最終結果已確定時提前結束,不會再計算右側的表達式。這個特性常被用來防止例外或延遲計算。
def is_positive(n):
return n > 0
def safe_divide(a, b):
# 若 b 為 0,直接回傳 None,避免 ZeroDivisionError
return b != 0 and a / b
在 b != 0 and a / b 中,若 b != 0 為 False,a / b 就不會被執行。
4. 運算子返回值與優先順序
| 運算子 | 優先級(從高到低) |
|---|---|
not |
最高 |
and |
中等 |
or |
最低 |
因此:
result = not a and b or c # 等同於 ((not a) and b) or c
如果想改變預設的結合方式,請使用括號明確分組。
程式碼範例
下面提供 5 個實用範例,說明如何在日常開發中使用邏輯運算子。
範例 1:簡易登入驗證
def login(username: str, password: str) -> bool:
"""檢查使用者名稱與密碼是否同時符合規則。"""
valid_user = username == "admin"
valid_pass = password == "S3cure!"
# 必須同時滿足兩個條件
return valid_user and valid_pass
print(login("admin", "S3cure!")) # True
print(login("admin", "wrong")) # False
這裡
and把兩個布林條件結合,只有兩者皆為True時才回傳True。
範例 2:使用 or 提供預設值
def get_config(key: str, config: dict, default=None):
"""從設定字典取得值,若不存在則回傳預設值。"""
return config.get(key) or default
settings = {"mode": "debug"}
print(get_config("mode", settings, "production")) # debug
print(get_config("timeout", settings, 30)) # 30
config.get(key)若回傳None(或其他假值),or會直接回傳右側的default。
範例 3:短路求值避免除以零
def safe_divide(a: float, b: float):
"""若 b 為 0,回傳 None;否則回傳商。"""
return b != 0 and a / b # b 為 0 時右側不會被執行
print(safe_divide(10, 2)) # 5.0
print(safe_divide(10, 0)) # False (可自行改成 None)
透過
and的短路特性,a / b只會在b != 0為True時才會執行。
範例 4:使用 not 反轉條件
def is_even(n: int) -> bool:
"""判斷是否為偶數。"""
return n % 2 == 0
def is_odd(n: int) -> bool:
"""利用 not 直接得到奇數判斷。"""
return not is_even(n)
print(is_odd(7)) # True
print(is_odd(8)) # False
not讓我們不必重複寫一次n % 2 != 0,程式更易讀。
範例 5:複合條件與括號
def can_access(user_role: str, is_active: bool, has_token: bool) -> bool:
"""
只有在使用者為 admin 且帳號啟用,或持有有效 token 時才允許存取。
"""
return (user_role == "admin" and is_active) or has_token
print(can_access("admin", True, False)) # True
print(can_access("guest", True, True)) # True
print(can_access("guest", False, False)) # False
這個例子展示了 括號 的必要性,避免因優先順序產生錯誤的邏輯。
常見陷阱與最佳實踐
| 陷阱 | 說明 | 解決方式 |
|---|---|---|
把 and/or 當成布林運算子 |
由於它們會回傳實際物件,有時會得到非布林值(如列表、字串)而產生意外結果。 | 若只需要布林結果,使用 bool(expr1 and expr2) 或明確比較 is True。 |
| 忽略短路求值的副作用 | 在右側有副作用(例如 I/O)時,可能因左側已決定結果而不會執行,導致程式行為不一致。 | 明確分離副作用,或使用完整的 if 判斷式。 |
混用 is 與 == 判斷真假 |
is 檢查物件身份,== 檢查等值。對於布林值使用 is 沒問題,但對於其他類型會產生錯誤。 |
只在比較 True、False、None 時使用 is;其餘情況使用 ==。 |
| 忘記優先順序 | not 的優先級最高,若不加括號容易產生「不是 A 且 B」與「不是 (A 且 B)」的差異。 |
使用括號明確表達意圖,或遵守「先 not 再 and 再 or」的規則。 |
把空容器視為 False |
有時需區分「容器空」與「布林值 False」的差別,直接使用 if container: 可能遮蔽錯誤。 |
若要檢查是否真的為 False,使用 is False;若只關心是否有內容,使用 if container:。 |
最佳實踐
- 明確寫出布林意圖:
if is_valid:比if is_valid == True:可讀性更佳。 - 利用短路求值防止例外:在存取字典或屬性前,先檢查前置條件。
- 保持條件簡潔:過長的單行條件可拆成多行或使用說明性的變數名稱。
- 測試真值邊界:特別是自訂類別的
__bool__/__len__,確保行為如預期。 - 使用括號提升可讀性:即使優先順序正確,括號也能讓程式碼更易於維護。
實際應用場景
| 場景 | 使用的邏輯運算子 | 為何適合 |
|---|---|---|
| 表單驗證 | and、or、not |
同時檢查多個欄位、提供預設值、反轉錯誤訊息。 |
| 權限控管 | and、or |
結合角色、狀態與 token 判斷是否允許存取。 |
| 配置讀取 | or |
當環境變數未設定時,使用程式內的預設值。 |
| 錯誤容忍 | and(短路) |
只有在前置條件成立時才執行可能拋出例外的程式碼。 |
| 資料過濾 | not、and、or |
篩選符合或排除特定條件的資料列。 |
例如在 Flask 或 Django 的視圖函式中,常會寫
if user.is_authenticated and (user.is_staff or user.has_perm('app.change_model')):
這裡同時運用了and、or,清楚表達「必須已登入,且是 staff 或具有特定權限」的邏輯。
總結
- 邏輯運算子
and、or、not是 Python 中處理真假判斷的基礎工具。 - 它們不僅返回布林值,還會回傳實際運算結果的物件,因此要注意真值測試與短路求值的行為。
- 正確掌握優先順序、括號使用以及真值測試的概念,可避免常見的錯誤與程式漏洞。
- 在日常開發(表單驗證、權限控管、設定管理、錯誤容忍等)中,善用這三個運算子能讓程式碼更簡潔、可讀且安全。
透過上述說明與範例,你現在應該能自信地在 Python 程式中使用邏輯運算子,寫出更具表達力與韌性的程式碼。祝你寫程式愉快! 🎉