這篇主要涉及Python物件的型別機制
有點繞, 一定要思維清晰的時候再看哦:)
一個例子
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
>>> a = 1 >>> a 1 >>> type(a) #等價的兩個 >>> type(type(a)) >>> type(int) #還是等價的兩個 >>> type(type(type(a))) >>> type(type(int)) |
我們反向推導一個int
物件是怎麼生成的.
1. 首先, 定義一種型別叫PyTypeObject
程式碼位置 Include/object.h
定義
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
typedef struct _typeobject { /* MARK: base, 注意, 是個變長物件*/ PyObject_VAR_HEAD const char *tp_name; /* For printing, in format "." */ //型別名 Py_ssize_t tp_basicsize, tp_itemsize; /* For allocation */ // 建立該型別物件時分配的記憶體空間大小 // 一堆方法定義, 函式和指標 /* Methods to implement standard operations */ printfunc tp_print; hashfunc tp_hash; /* Method suites for standard classes */ PyNumberMethods *tp_as_number; // 數值物件操作 PySequenceMethods *tp_as_sequence; // 序列物件操作 PyMappingMethods *tp_as_mapping; // 字典物件操作 // 一堆屬性定義 .... } PyTypeObject; |
說明
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
1. tp_name 型別名, 這裡是"type" 2. PyVarObject_HEAD_INIT(&PyType_Type, 0) PyVarObject_HEAD_INIT, 這個方法在 Include/object.h中, 等價於 ob_refcnt = 1 *ob_type = &PyType_Type ob_size = 0 即, PyType_Type的型別是其本身!1. tp_name 型別名, 這裡是"type" 2. PyVarObject_HEAD_INIT(&PyType_Type, 0) PyVarObject_HEAD_INIT, 這個方法在 Include/object.h中, 等價於 ob_refcnt = 1 *ob_type = &PyType_Type ob_size = 0 即, PyType_Type的型別是其本身! |
所有Type都是PyTypeObject的”例項”: PyType_Type/PyInt_Type
2. 然後, 用PyTypeObject初始化得到一個物件PyType_Type
程式碼位置 Objects/typeobject.c
定義
1 2 3 4 5 6 7 8 9 10 11 |
PyTypeObject PyType_Type = { PyVarObject_HEAD_INIT(&PyType_Type, 0) "type", /* tp_name */ sizeof(PyHeapTypeObject), /* tp_basicsize */ sizeof(PyMemberDef), /* tp_itemsize */ (destructor)type_dealloc, /* tp_dealloc */ // type物件的方法和屬性初始化值 ..... }; |
說明
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 |
1. tp_name 型別名, 這裡是"type" 2. PyVarObject_HEAD_INIT(&PyType_Type, 0) PyVarObject_HEAD_INIT, 這個方法在 Include/object.h中, 等價於 ob_refcnt = 1 *ob_type = &PyType_Type ob_size = 0 即, PyType_Type的型別是其本身!1. tp_name 型別名, 這裡是"type" 2. PyVarObject_HEAD_INIT(&PyType_Type, 0) PyVarObject_HEAD_INIT, 這個方法在 Include/object.h中, 等價於 ob_refcnt = 1 *ob_type = &PyType_Type ob_size = 0 即, PyType_Type的型別是其本身!1. tp_name 型別名, 這裡是"type" 2. PyVarObject_HEAD_INIT(&PyType_Type, 0) PyVarObject_HEAD_INIT, 這個方法在 Include/object.h中, 等價於 ob_refcnt = 1 *ob_type = &PyType_Type ob_size = 0 即, PyType_Type的型別是其本身! |
結構
第一張圖, 箭頭表示例項化
(google doc用不是很熟找不到對應型別的箭頭)
第二張圖, 箭頭表示指向
使用
1 2 3 4 5 |
# 1. int 的 型別 是`type` >>> type(int) # 2. type 的型別 還是`type`, 對應上面說明第二點 >>> type(type(int)) |
注意: 無論任何時候, ob_type指向的是 PyTypeObject的例項: PyType_Type/PyInt_Type…
3. 再然後, 定義具體的型別, 這裡以PyInt_Type為例子
程式碼位置 Objects/intobject.c
定義
1 2 3 4 5 6 7 8 9 10 11 12 |
PyTypeObject PyInt_Type = { PyVarObject_HEAD_INIT(&PyType_Type, 0) "int", sizeof(PyIntObject), 0, // int型別的相關方法和屬性值 .... (hashfunc)int_hash, /* tp_hash */ }; |
說明
1 2 3 4 5 6 7 |
1. "int" PyInt_Type的型別名是int 2.PyVarObject_HEAD_INIT(&PyType_Type, 0) PyInt_Type的 *ob_type = &PyType_Type |
結構
使用
1 2 3 4 5 |
>>> type(1) <type 'int'> >>> type(type(1)) <type 'type'> |
4. 最後, 生成一個整數物件int
程式碼位置 Include/intobject.h
定義
1 2 3 4 |
typedef struct { PyObject_HEAD long ob_ival; } PyIntObject; |
結構
1 2 3 4 5 |
1. PyIntObject為整數型別 2. 宣告一個整數後得到整數物件 3. 物件ob_type指向PyInt_type物件 |
到這裡, 總結下
1 2 3 4 5 6 7 8 9 10 11 12 13 |
1. 一切都是物件 2. PyType_Type / PyInt_Type / PyString_Type ....等 這些是`型別物件`, 可以認為是同級, 都是PyTypeObject這種`型別`的例項! 3. 雖然是同級, 但是其他PyXXX_Type, 其型別指向 PyType_Type PyType_Type 的型別指向自己, 它是所有型別的`型別` 4. PyTypeObject 是一個變長物件 5. 每個object, 例如PyIntObject都屬於一種`型別` object初始化時進行關聯 |
多型是如何實現的?
物件的多型, 例如hash
1 2 3 4 |
>>> hash(1) 1 >>> hash("abc") 1453079729188098211 |
從上面資料結構可以看到, 方法及屬性, 在不同Type例項化時就確定了
1 2 3 4 5 6 7 8 9 10 11 |
PyTypeObject PyInt_Type = { ... (hashfunc)int_hash, /* tp_hash */ ... } PyTypeObject PyString_Type = { ... (hashfunc)string_hash, /* tp_hash */ ... } |
Python內部傳遞的是泛型指標PyObject *
, 函式呼叫時, 找到其型別* ob_type
, 然後呼叫
1 |
object -> ob_type -> tp_hash |
即: 大量函式指標決定了該型別的具體行為
changelog
1 |
2014-08-05 first version |
打賞支援我寫出更多好文章,謝謝!
打賞作者
打賞支援我寫出更多好文章,謝謝!
任選一種支付方式