固定的記憶體空間
object 初始化後大小不準變動, 這個限制帶來一個好處: 大小不變表示不可能要求更大的記憶體空間; 不要求更大的記憶體空間表示不可能要求重配一塊區域, 因此也不會改變 address, 所以, 不用擔心之後要更改任何 pointer 的值。
這讓我想到 MySQL InnoDB 的設計採用 clustered index 存資料, clustered index 裡的 index columns = primary key (PK) 接著針對其它 index (non-clustered index), MySQL 改存 PK 的值, 而不是存 data table 的 physical location (MyISAM 的作法)。
這個設計帶來兩個影響
- 優點: data row 改變位置時 (B-Tree 常分割或合併 node), 不用更新 indexes
- 缺點: indexes (非 PK) 得先找到 PK, 再用 PK 取資料, 多了一步
不過 MySQL 針對缺點又做了 InnoDB cache, 讓常取的資料能一步就取到資料, 但也增加維護成本, 這是另一個議題了。
PyObject
C 裡沒有 OO 的語法, Python 用 #ifdef 來增加選擇性欄位, 用 #define 擴充欄位並保留同樣的 address offset。所有 object 的 struct 開頭都是
typedef struct { PyObject_HEAD ... } PyXObject;
PyObject_HEAD 是巨集, 最簡單的定義如下:
#define PyObject_HEAD \\\\ int ob_refcnt; struct _typeobject *ob_type;
另有 PyObject_VAR_HEAD 幫動態的物件加上 ob_size 欄位:
#define PyObject_VAR_HEAD \\\\ PyObject_HEAD int ob_size;
所以, 最基本的 python object 和含有不等量的 object 定義如下:
typedef struct { PyObject_HEAD } PyObject; typedef struct { PyObject_VAR_HEAD } PyVarObject;
類別 int 的定義如下:
typedef struct { PyObject_HEAD long ob_ival; } PyIntObject;
這個作法漂亮的地方在於, 彈性地定義不同類型物件用到的欄位, 又能讓所有物件有共通的開頭欄位。於是, PyObject* 可以指向任何物件, 並能放心地假設:
- 第一個欄位是 ob_refcnt
- 第二個欄位是 ob_type
若用 PyVarObvject*, 則能再假設
- 第三個欄位是 ob_size
以基本型別為例:
int | float | string | list |
---|---|---|---|
ob_refcnt | ob_refcnt | ob_refcnt | ob_refcnt |
ob_type | ob_type | ob_type | ob_type |
ob_ival | ob_fval | ob_size | ob_size |
ob_shash | ob_item | ||
... | ... |
沒有留言:
張貼留言