本篇是故事三的「查證」篇。
本篇要回答:懷疑資料在某處變形時,應該保存哪些證據?
Day 11 的逗號事故有個殘酷的細節:debug 的前幾輪,我其實「看過」那個值。print(result) 印出來的東西看起來有值、不是 None、不是空——於是嫌疑人被當場釋放。問題出在 print 預設走 str(),而很多型別的字串外觀足夠像正常資料,讓人看一眼就放行。
當時的採證習慣是「印出來看看」,而且只印值本身。這個習慣背後的假設是:值長得對,型別就對。單元素 tuple 恰好是這個假設的反例——(42,) 印成 (42,) 還算顯眼,但當值是一包字典或一串文字時,掃過去很容易只注意內容、忽略最外層多包的那一層殼。
資料採證的最小升級,是把「印值」換成「印身分」:
print(repr(value)) # 印出無歧義的表示:(42,) 與 42 一眼可分
print(type(value)) # 直接回答「它是什麼」
repr 的存在意義就是給人採證用的無歧義表示;type 則不給任何外觀模糊的空間。這兩行是資料事故的 sys.executable——先問身分,再談對錯。
完整的採證清單,對照 Day 07 的環境版:
區分證據等級。已確認事實:repr 與 type 的行為(已執行驗證)。合理推論:當時若第一輪就印 repr,滑行距離會縮短為零——這是推論,因為歷史無法重跑。
留下一條採證紀律,也是本篇結論:
值看起來存在,不代表它仍然是下游答應接收的那種東西。
下一篇(Day 13)重建完整的傳遞路徑:一個 tuple,如何一路通過那些對它毫無意見的函式。