題幹與適用場景
團隊升級到 Python 3.14,希望讓模板處理器在串接字串前檢查插值值。請解釋 t-string 產生什麼物件、如何遍歷片段,以及如何避免把模板 API 誤當成自動轉義。
PEP 750 為 Python 3.14 引入模板字串。t"..." 不會直接產生 str,而是產生 string.templatelib.Template,其中保留靜態字串片段與插值物件,應用程式可以在最後串接前執行驗證、轉義或領域轉換。
面試官考察點
重點包括:區分 f-string 的立即字串化與 t-string 的結構化結果、理解 Template 與 Interpolation 欄位、處理原始值與格式說明、設計情境相關轉義、控制副作用,以及相容舊版 Python。
30 秒回答框架
「我會先強調 t-string 不是自動安全輸出。它把模板解析成靜態片段與插值物件,渲染器可以檢查原始值、表達式文字、轉換與格式說明,再依 SQL、HTML 或日誌情境執行專用編碼。模板本身不應執行任意字串串接;我會限制允許的值型別,測試巢狀模板、格式說明、例外與舊版回退,並把最終輸出當成不可信資料繼續驗證。」
分步驟深入解答
第一步:區分 f-string 與 t-string
f-string 會先求值並格式化成 str,中間結構不可恢復。t-string 使用 t 前綴,結果是 Template;靜態文字與插值仍分開,渲染器可在合併前檢查每一項。
第二步:理解核心物件
模板由字串片段與 Interpolation 組成。插值記錄值、表達式文字、轉換標記與格式說明,方便策略依來源或目標情境決定。不要假設遍歷結果就是已安全的最終字串。
第三步:寫出最小處理器
以下處理器只示範結構化遍歷,實際系統仍需依情境編碼:
from string.templatelib import Template
def render_plain(template: Template) -> str:
parts = []
for item in template:
if isinstance(item, str):
parts.append(item)
else:
parts.append(str(item.value))
return "".join(parts)
message = t"Hello, {name}!"str(item.value) 只適合沒有安全要求的純文字示例;SQL、HTML、Shell 與日誌必須使用各自的參數化或編碼 API。
第四步:處理轉換與格式說明
插值可能帶有 !s、!r 或格式說明。渲染器應先決定是否允許轉換,再對轉換後的值套用目標情境編碼。不能把 repr 當作 HTML 轉義,也不能讓格式說明繞過型別白名單。
第五步:避免副作用表達式
t-string 仍會求值插值表達式來建立 Interpolation。模板處理器不能把 t-string 當成沙箱;若模板來源不可信,風險在模板建立階段已存在。對外掛或使用者輸入只接受資料佔位符,禁止動態執行表達式。
第六步:依輸出情境選擇策略
純文字可以依允許型別轉換;HTML 應使用經稽核的 HTML 轉義器;SQL 應使用驅動參數綁定;Shell 應避免串接並使用參數陣列;結構化日誌應傳遞欄位而非拼成一行。Template 提供結構,不取代這些安全邊界。
第七步:相容版本與 API 發現
Python 3.14 提供 string.templatelib。支援舊版時應透過版本適配選擇既有模板庫或明確降級為 f-string,不要假裝能在舊直譯器保留插值結構。啟動時檢查執行時版本,CI 覆蓋每個支援版本。
第八步:測試與觀測
測試靜態片段、巢狀 t-string、格式說明、例外、物件 format 副作用與大型模板。記錄策略拒絕的值型別與模板來源,但不要把插值內容寫進可能公開的日誌;對輸出做情境專屬安全回歸。
設計取捨與邊界
結構化處理還是簡單串接
需要稽核、國際化或多種輸出目標時,保留結構能讓策略前移;一次性純文字腳本使用 f-string 更簡單。團隊應依風險與複用範圍選擇,不為所有字串引入模板管線。
彈性格式還是可預測型別
允許任意 format 會提高表現力,也會引入副作用與型別漂移。公共渲染器應限制值型別、轉換與格式說明,並對拒絕給出可診斷錯誤。
模板物件還是最終字串
Template 適合在邊界內傳遞,最終輸出仍應在傳送、儲存或執行前再次依情境檢查。不要把 Template 當作已完成編碼的安全令牌。
失敗演練與演進計畫
HTML 轉義被繞過
讓插值實作自訂 str 回傳帶標籤內容,確認純 str 轉換不會自動安全;改用情境編碼並加入惡意值回歸。
格式說明觸發例外
使用不支援的格式說明和物件 format 拋錯,驗證處理器能定位具體插值並拒絕整次渲染,而不是回傳半截輸出。
舊直譯器誤執行
在 Python 3.13 啟動同一模組,確認版本檢查給出清晰錯誤或走明確相容實作,不能把語法錯誤留到生產。
常見誤區與追問
誤區一:認為 t-string 會自動轉義
追問:它解決了什麼?它保留結構,方便應用程式在串接前做策略處理;SQL、HTML 等安全仍由專用 API 負責。
誤區二:認為插值表達式不會執行
追問:何時求值?建立 t-string 時表達式會求值並記錄結果,因此不可信模板不能透過 t-string 取得沙箱能力。
誤區三:把 repr 當作安全編碼
追問:為什麼不行?repr 是除錯表示,不保證符合 HTML、SQL、Shell 或日誌欄位的編碼規則。
延伸追問與參考答案
t-string 適合取代所有 f-string 嗎?
不適合。只有需要在合併前檢查或轉換插值的邊界才有結構收益;普通純文字仍可使用 f-string。
如何為 SQL 設計渲染器?
不要生成 SQL 字串;把靜態片段與值映射到驅動的參數佔位符,值透過參數綁定傳遞,模板只描述語法結構。
如何處理舊版 Python?
啟動時檢查版本,在 3.14 使用 string.templatelib,舊版使用既有模板實作或明確不支援,並用同一組安全語意測試驗證差異。