特殊方法
- 資料模型對 Python 來說是一種「框架」,這個框架(可以想成 Python 的解譯器 Interpreter)會呼叫特定的方法(指 method),這個特定的方法就是 Dunder Method
- 當你實作了
__getitem__
,就代表類別實例可以是可迭代(iterable),且支援了 indexing、slicing、函式庫如 random.choice
等
- 若可迭代物件沒有實作
__contains__
,在 in
運算子下的預設的行為是循序掃描
len()
對於內建型態(如 list、str、bytearray),解譯器並非呼叫 __len__
,而是回到底層的 C 結構查詢,因為速度快很多 —— 這也說明了為什麼是 len(collection)
而不是 collection.len
,這是一種「在內建物件效率與語言一致性之間取得平衡」
for
語句私下是呼叫 iter()
再呼叫 __iter__()
- 一般而言,你的程式不該自己呼叫特殊方法,而是透過內建方法(如 len、iter、str)
- 交互式終端與除錯程式會對運算式的結果呼叫
repr()
__repr__
回傳的字串必須精確,盡可能匹配原始碼,好表示「物件如何建立的」以利再次重建
- 沒有自訂的
__str__
,解譯器會呼叫 __repr__
提供回饋
- 反向運算子 (reverse operator) 應用在交換律的後備機制如
a * b
及 b * a
- 擴增賦值運算子 (augmented assignment operator) 意在結合中輟運算 (infix) 與賦值行為,如
a <<= b
- 「讓使用者使用核心開發人員所使用的工具」,我的理解是,將底層 API 開放給上層使用
- 「特殊方法其實是魔術方法的相反」,魔術功能通常意指「你不能在自己定義的物件中模擬這些功能」
序列
- 牢記可變 VS. 不可變、容器序列 VS. 一般序列的不同
- List comprehension 只做一件事:建構新序列
- tuple 可以當成「不可變序列」來用,也可當成沒有欄位名稱的「紀錄」(有 unpacking 的優勢)
- 變數名
_
翻譯成「啞變數」(使用底線有缺點,會被當成 gettext 的函數別名)
- 當賦值的對象是切片時,賦值物件必須是 iterable,如
l[2:5] = [20, 30]
- 序列的
+
與 *
一定都是建立新物件
+=
(原地算法)的特殊方法是 __iadd__
, i 代表 in-place,如果 __iadd__
沒有被實作的話,Python 會退而呼叫 __add__
,可以解讀成「是否真的是原地算法,取決於運算哪種物件」—— 同一個概念可以套用到 *=
- 檢視 Python 的 bytecode:
dis.dis('<your code here>')
- 重要的 Python API 慣例:當函式或方法就地改變物件(沒有建立新的物件)時,必須回傳 None,簡單的範例是
list.sort()
,反例是 sorted(list)
- 另一種快速的數值儲存方式,是使用 pickle 模組來做物件序列化,使用
pickle.dump
來儲存一個陣列的浮點數幾乎和 array.tofile
一樣快
- 內建的
memoryview
類別是 Python 的一個廣義 NumPy 陣列結構,可以用它在資料結構間共用記憶體(PIL、SQLite、NumPy 陣列等),而不需要先做複製
- 移除 deque 中間的項目並不是那麼快,它其實最適合在兩端進行操作
- queue 函式庫實作的佇列如 Queue、LifoQueue 用來在執行緒之間進行安全通訊
- Python 的 sort 是使用 Timesort,根據資料的排序狀況來決定採用 MergeSort 或是 InsertionSort
Read More »Fluent Python 讀書筆記(一)