Python 3.15 的 sentinel:把「沒填」和「刻意留空」分開

編輯資料時,「這次沒有提供新標籤」和「請把標籤清掉」是兩個不同的意思。如果函式把兩者都當成 None,程式就容易猜錯。

Python 在 2026 年 10 月 9 日發布的 3.15,新增內建的 sentinel,讓我們替「沒有提供」準備一個專用標記。這次從 Python 官方 RSS 挑出這項小功能,看看它能解決什麼問題。哨兵值的做法早已存在,新的是這個內建建構方式。Python 正式版公告

先看一個只回傳說明文字的例子。它不會真的改動帳號、檔案或資料庫,也不需要上網或安裝套件;本例使用 Python 3.15 新增的內建 sentinel:

MISSING = sentinel("MISSING")

def label_action(label=MISSING):
    if label is MISSING:
        return "保留原標籤"
    if label is None:
        return "清除標籤"
    return f"改為:{label}"

print(label_action())
print(label_action(None))
print(label_action("程式筆記"))

依照這段邏輯,三次呼叫會分別得到:

  • 沒傳參數:保留原標籤。
  • 明確傳入 None:清除標籤。
  • 傳入「程式筆記」:改為:程式筆記。

這裡「None 代表清除」是我們替函式訂的規則,不是 Python 自動賦予所有 None 的意思。sentinel 的工作,是讓「根本沒提供」有自己獨立的身分。PEP 661 設計背景

兩個容易踩到的地方:

  1. 用 is MISSING 判斷,別改成 if not label。空字串、0 和 None 可能各有用途,而且 sentinel 本身的布林值是真。
  2. 建立一次後重用 MISSING。再寫一次 sentinel("MISSING") 會得到另一個物件,不會因為名字相同就成為同一個標記。Python 官方使用說明

如果函式根本不需要區分「未提供」與 None,維持原本簡單的設計就好,不必把每一個 None 都換掉。範例已按官方文件核對語意,但尚未在 Python 3.15 環境實際執行。

版本核對:截至 10 月 22 日,3.15 系列已有 10 月 21 日發布的 3.15.1;本文介紹「3.15 新增」的功能,不是把 3.15.0 當成最新修補版本。Python 修補版公告

你寫表單或更新資料的函式時,會怎麼區分「未提供」「清空」和「新值」?