Skip to content

duck typing

Fluent Python 讀書筆記(三)

物件參考、可變性與重複使用

  • 「變數是標籤,不是盒子」
  • 使用參考變數 (reference variable) 時,說「變數被指派給一個物件」會比較合理,畢竟——物件是在賦值之前建立的
  • 兩個變數被指派到同一個物件時,這兩個變數互為「別名(alias)」
  • 「每一個物件都有一個身份(ID)、一個型態跟一個值」,在 CPython,這個身份是 id(),回傳物件的記憶體位置(不同解譯器可能會使用不同東西作為 ID)
  • == 比較物件的值;is 比較物件的 ID
  • is== 快,因為它無法多載(不需要尋找或呼叫特殊方法來演算出一個值)
  • 原始物件的 __eq__ 會比較 ID,但大多數覆寫 __eq__ 的情況通常會加入或使用別的比較
  • tuple 不可變的意思是「保存在它當中的物件參考 ID 不變」,即使 tuple 可能存了可變的物件
  • 淺複製 (shallow copy) 即容器本身會被複製,但新的容器裡面保存的是舊的參考,例如 arr[:]arr.copy()copy(arr)
  • 實作 deep copy 要小心物件可能會循環參考 (Ring),要判斷物件是否已經複製過
  • 覆寫 __copy____deepcopy__ 可以控制 copy.copy()copy.deepcopy() 的行為
  • Python 函式傳遞的是參考(call by sharing) —— 即函數的參數 (parameter) 會指向引數 (argument) 的參考,換句話說,「函式內的參數就是其實際引數的別名」
  • 同上,這也是為什麼「函式的預設參數不要使用可變型態」,簡單的改良:預設為 None,在函式中判斷是否初始化新的可變物件
  • del 刪除的是參考,而不是物件本身;物件只有在「參考數量變成零」的情況下才有可能被回收,這種銷毀可能不是立即性的
  • CPython 回收記憶體的演算法主要是計算參考數量,這個參考數量存在物件本身,但假若有循環參考時,容易發生 memory leak
  • 在 CPython 的實作下,對 tuplestrbytes而言 s[:] 不會製作複本,而是回傳物件的參考
  • 在使用執行緒時,修改可變物件很難得到正確的結果:無法適當同步的執行序,會導致資料損毀;過度同步的執行序,會造成 deadlock

弱參考 (Weak Reference)

  • 常用在使用快取的情境下,須要「參考一個不會被保存太久的物件」
  • 弱參考是一種可呼叫的物件,它會回傳參考的物件,或者 None
  • 使用弱參考而非賦值,就不會讓物件的「參考數量」增加
  • 考慮使用 WeakKeyDictionaryWeakValueDictionaryWeakSetfinalize 這些內部使用弱參考的高階界面,而非自己用 weakref.ref 實作
  • 因為實作的限制,listdict 的子類別可以被弱參考(原始型態不行),而 inttuple 則完全無法被弱參考


字串常值的共用,是一種優化技術,稱為 interning,Cpython 會對小型的整數使用相同的技術,來避免沒必要的重複

Read More »Fluent Python 讀書筆記(三)