Python 基本語法 ── 識別字與命名慣例(snake_case)
簡介
在任何程式語言中,識別字(identifier) 都是程式的「名片」:變數、函式、類別、模組等都需要透過有意義且可辨識的名稱來存取。若名稱隨意、難以閱讀,程式碼的可維護性、可讀性就會大幅下降。
Python 社群長期以來推崇 PEP 8(Python 程式風格指南)作為統一的編碼標準,其中最常見的命名慣例就是 snake_case——所有字母小寫,單字之間以底線(_)分隔。熟練掌握 snake_case 不僅能讓你的程式碼看起來「像 Python」;更重要的是,它能降低團隊合作時的溝通成本,讓程式碼審查、除錯變得更順暢。
本篇文章將從 識別字的語法規則、snake_case 的具體寫法、實務範例、常見陷阱與最佳實踐,一步步帶你建立正確的命名觀念,無論是剛踏入程式世界的新人,或是已經有幾年開發經驗的中階工程師,都能從中獲得實用的技巧與啟發。
核心概念
1. 識別字的基本語法
| 規則 | 說明 |
|---|---|
| 必須以 字母 (A‑Z, a‑z) 或底線 (_) 開頭 | 數字只能出現在開頭之後,例如 var1 合法、1var 不合法。 |
| 後續字元可以是 字母、數字或底線 | my_var2, _temp, data_2023 都是合法的識別字。 |
| 大小寫敏感 | value 與 Value 被視為不同的變數。 |
不能使用 Python 關鍵字(如 for, class, def)作為名稱 |
若一定要使用,可在名稱後加底線,例如 class_。 |
| Unicode 允許使用 非 ASCII 字元(如中文、日文) | 雖然語法允許,但不建議在程式碼中使用,以免跨平台相容性問題。 |
小技巧:在 Python REPL 中,使用
keyword.iskeyword('for')可以快速檢查字串是否為關鍵字。
2. 為什麼使用 snake_case?
- 可讀性:底線明確分隔單字,閱讀時自然斷句。
- 符合 PEP 8:Python 官方風格指南明確規定,遵循可避免 lint 工具的警告。
- 跨平台一致性:不同作業系統的檔案系統對大小寫敏感度不同,統一使用小寫能減少意外。
- 團隊協作:統一的命名慣例讓新加入的成員快速上手,減少溝通成本。
注意:類別名稱則使用 PascalCase(首字母大寫),例如
MyClass;常數則使用 UPPER_SNAKE_CASE,例如MAX_CONNECTIONS。本篇聚焦於變數與函式的 snake_case。
3. snake_case 的寫法原則
| 原則 | 範例 | 說明 |
|---|---|---|
| 全小寫 | user_name |
絕不使用大寫字母。 |
| 單字以底線分隔 | total_price |
多個單字時,用 _ 連接。 |
| 避免連續底線 | http_response (✔) vs http__response (✘) |
連續底線會降低可讀性,且易與「私有變數」__private 混淆。 |
| 不要以底線結尾 | file_path (✔) vs file_path_ (✘) |
結尾底線常被誤用於保留字或特殊情況。 |
| 盡量使用具體語意 | max_retry_attempts (✔) vs x (✘) |
具體名稱能讓程式碼自說自話。 |
程式碼範例
以下示範 5 個常見情境,從變數宣告、函式命名到模組匯入,皆採用 snake_case。
# 範例 1:變數命名
user_id = 12345 # 使用底線分隔單字
total_price = 199.99 # 數值型變數
is_active = True # 布林值以 is_ / has_ 開頭較易閱讀
# 範例 2:函式命名
def calculate_discount(price: float, rate: float = 0.1) -> float:
"""
計算折扣後的價格。
:param price: 原始價格
:param rate: 折扣率,預設 10%
:return: 折扣後的金額
"""
discounted_price = price * (1 - rate)
return round(discounted_price, 2)
# 呼叫函式
final_price = calculate_discount(total_price)
print(f"折扣後金額:{final_price}")
# 範例 3:類別方法與私有屬性 (仍使用 snake_case)
class OrderProcessor:
def __init__(self, order_id: int):
self.order_id = order_id
self._is_processed = False # 單底線表示「受保護」屬性
def process_order(self) -> None:
"""執行訂單處理流程"""
if not self._is_processed:
# ... 省略實作細節 ...
self._is_processed = True
print(f"訂單 {self.order_id} 已處理。")
# 使用類別
processor = OrderProcessor(user_id)
processor.process_order()
# 範例 4:模組匯入與別名
import datetime as dt # 使用簡短且易讀的別名
current_time = dt.datetime.now()
print(f"現在時間:{current_time}")
# 範例 5:常數命名(仍遵循 snake_case 的變形)
MAX_RETRY_ATTEMPTS = 5 # 常數採用全大寫
重點說明
- 變數、函式皆使用 全小寫 + 底線。
- 私有或受保護屬性以單底線開頭,避免與「魔術方法」
__init__混淆。- 模組別名亦採用小寫,保持一致性。
常見陷阱與最佳實踐
| 陷阱 | 說明 | 解決方案 |
|---|---|---|
| 使用大寫字母 | UserName、TotalPrice 看起來像類別名稱,易造成混淆。 |
嚴格遵守 全小寫 原則,若需要類別則改用 PascalCase。 |
| 連續底線 | http__response、__private_var(非魔術方法)會讓程式碼難以閱讀。 |
只在特殊情況(如 __init__、__str__)使用雙底線;一般變數避免。 |
| 與關鍵字衝突 | class = 5 會直接產生 SyntaxError。 |
使用底線後綴(class_)或重新命名。 |
| 過長或過短 | x, y 雖簡短,但意義不明;this_is_a_very_long_variable_name_exceeding_reasonable_length 讀起來也吃力。 |
取 適中長度,兼具語意與可讀性,例如 user_age、order_total。 |
| 不一致的命名 | 同一模組內部有 userName、user_name 兩種寫法。 |
設定團隊 lint 規則(如 flake8、pylint)自動檢查。 |
最佳實踐清單
- 統一風格:在專案根目錄加入
.flake8或pyproject.toml,啟用pep8-naming插件自動偵測違規。 - 語意化:變數名稱應描述其用途,如
file_path而非fp,除非在局部範圍極短。 - 避免縮寫:除非是業界公認的縮寫(如
id,url),否則盡量寫全。 - 使用類別與函式的動詞:函式名稱以動詞開頭,如
fetch_data、save_to_file,讓呼叫意圖一目了然。 - 保持一致的底線數量:單底線分隔單字,雙底線僅保留給魔術方法或特殊用途。
實際應用場景
1. 資料分析腳本
在資料科學專案中,常會寫大量的 資料清理 與 特徵工程 程式。以下是一段典型的 Pandas 操作,全部使用 snake_case:
import pandas as pd
def load_sales_data(csv_path: str) -> pd.DataFrame:
"""讀取銷售資料 CSV,並將日期欄位轉為 datetime」"""
df = pd.read_csv(csv_path, parse_dates=['sale_date'])
return df
def clean_sales_data(df: pd.DataFrame) -> pd.DataFrame:
"""資料清理:去除缺失值、過濾負數金額"""
df = df.dropna(subset=['sale_amount'])
df = df[df['sale_amount'] >= 0]
return df
sales_df = load_sales_data('data/sales_2023.csv')
sales_df = clean_sales_data(sales_df)
print(sales_df.head())
load_sales_data、clean_sales_data皆以 動詞 + 名詞 命名,清楚表達功能。- 變數
sales_df、csv_path皆遵循 snake_case,讓腳本在多人協作時不會產生命名衝突。
2. Web API 後端開發
在 Flask 或 FastAPI 等框架中,路由函式的名稱同樣使用 snake_case,配合路由字串的 kebab-case(如 /user-profile)形成一致的命名層次:
from fastapi import FastAPI, HTTPException
app = FastAPI()
users_db = {}
def get_user_by_id(user_id: int) -> dict:
"""根據 user_id 取得使用者資料"""
return users_db.get(user_id)
@app.get("/users/{user_id}")
def read_user(user_id: int):
user = get_user_by_id(user_id)
if not user:
raise HTTPException(status_code=404, detail="User not found")
return user
read_user、get_user_by_id都是 snake_case,與 URL 路徑的語意相呼應。- 這樣的統一命名可讓前端工程師快速對應 API 文件,減少溝通成本。
3. 自動化測試
在 pytest 中,測試函式必須以 test_ 開頭。配合 snake_case,可直接看出測試的焦點:
def test_calculate_discount_returns_correct_value():
assert calculate_discount(100, 0.2) == 80.0
test_calculate_discount_returns_correct_value完全遵守 snake_case,讓測試報告易於閱讀與維護。
總結
- 識別字 是程式碼的基礎,必須遵守語法規則(開頭字母或底線、大小寫敏感、避免關鍵字)。
- snake_case 是 Python 官方推薦的變數與函式命名慣例,具備高可讀性、跨平台一致性與團隊協作友好等優點。
- 實務上,從 資料分析、Web API 到 自動化測試,均可看到 snake_case 的廣泛應用。
- 透過 lint 工具、一致的命名規則,可以有效避免常見陷阱(大寫、連續底線、與關鍵字衝突),提升程式碼品質。
掌握了 snake_case,不只是寫出符合 PEP 8 的程式,更是培養良好程式設計習慣的第一步。未來當你在更大型的專案或多語言環境中工作時,這套命名哲學將持續為你帶來 可讀、可維護、可擴充 的程式碼基礎。祝你在 Python 的旅程中,寫出既美觀又實用的程式!