878
Python
Python 源碼閱讀:類型
這篇主要涉及Python對象的類型機製
有點繞, 一定要思維清晰的時候再看哦:)
一個例子
1
>>>type(a)
#等價的兩個
>>>type(type(a))
>>>type(int)
#還是等價的兩個
>>>type(type(type(a)))
>>>type(type(int))
我們反向推導一個int對象是怎麼生成的.
1. 首先, 定義一種類型叫PyTypeObject
代碼位置 Include/object.h
定義
typedefstruct_typeobject{
/* MARK: base, 注意, 是個變長對象*/
PyObject_VAR_HEAD
constchar*tp_name;/* For printing, in format "." *///類型名
Py_ssize_ttp_basicsize,tp_itemsize;/* For allocation */// 創建該類型對象時分配的內存空間大小
// 一堆方法定義, 函數和指針
/* Methods to implement standard operations */
printfunctp_print;
hashfunctp_hash;
/* Method suites for standard classes */
PyNumberMethods *tp_as_number;// 數值對象操作
PySequenceMethods *tp_as_sequence;// 序列對象操作
PyMappingMethods *tp_as_mapping;// 字典對象操作
// 一堆屬性定義
....
}PyTypeObject;
說明
1.tp_name
類型名,這裏是"type"
2.PyVarObject_HEAD_INIT(&PyType_Type,)
PyVarObject_HEAD_INIT,這個方法在Include/object.h中,
等價於
ob_refcnt=1
*ob_type= &PyType_Type
ob_size=
即,PyType_Type的類型是其本身!1.tp_name
類型名,這裏是"type"
2.PyVarObject_HEAD_INIT(&PyType_Type,)
PyVarObject_HEAD_INIT,這個方法在Include/object.h中,
等價於
ob_refcnt=1
*ob_type= &PyType_Type
ob_size=
即,PyType_Type的類型是其本身!
所有Type都是PyTypeObject的”實例”: PyType_Type/PyInt_Type
2. 然後, 用PyTypeObject初始化得到一個對象PyType_Type
代碼位置 Objects/typeobject.c
定義
PyTypeObjectPyType_Type={
PyVarObject_HEAD_INIT(&PyType_Type,)
"type",/* tp_name */
sizeof(PyHeapTypeObject),/* tp_basicsize */
sizeof(PyMemberDef),/* tp_itemsize */
(destructor)type_dealloc,/* tp_dealloc */
// type對象的方法和屬性初始化值
.....
};
說明
1.tp_name
類型名,這裏是"type"
2.PyVarObject_HEAD_INIT(&PyType_Type,)
PyVarObject_HEAD_INIT,這個方法在Include/object.h中,
等價於
ob_refcnt=1
*ob_type= &PyType_Type
ob_size=
即,PyType_Type的類型是其本身!1.tp_name
類型名,這裏是"type"
2.PyVarObject_HEAD_INIT(&PyType_Type,)
PyVarObject_HEAD_INIT,這個方法在Include/object.h中,
等價於
ob_refcnt=1
*ob_type= &PyType_Type
ob_size=
即,PyType_Type的類型是其本身!1.tp_name
類型名,這裏是"type"
2.PyVarObject_HEAD_INIT(&PyType_Type,)
PyVarObject_HEAD_INIT,這個方法在Include/object.h中,
等價於
ob_refcnt=1
*ob_type= &PyType_Type
ob_size=
即,PyType_Type的類型是其本身!
結構
第一張圖, 箭頭表示實例化(google doc用不是很熟找不到對應類型的箭頭)
第二張圖, 箭頭表示指向
使用
# 1. int 的 類型 是`type`
>>>type(int)
# 2. type 的類型 還是`type`, 對應上麵說明第二點
>>>type(type(int))
注意: 無論任何時候, ob_type指向的是 PyTypeObject的實例: PyType_Type/PyInt_Type…
3. 再然後, 定義具體的類型, 這裏以PyInt_Type為例子
代碼位置 Objects/intobject.c
定義
PyTypeObjectPyInt_Type={
PyVarObject_HEAD_INIT(&PyType_Type,)
"int",
sizeof(PyIntObject),
,
// int類型的相關方法和屬性值
....
(hashfunc)int_hash,/* tp_hash */
};
說明
1."int"
PyInt_Type的類型名是int
2.PyVarObject_HEAD_INIT(&PyType_Type,)
PyInt_Type的
*ob_type= &PyType_Type
結構
使用
>>>type(1)
>>>type(type(1))
4. 最後, 生成一個整數對象int
代碼位置 Include/intobject.h
定義
typedefstruct{
PyObject_HEAD
longob_ival;
}PyIntObject;
結構
1.PyIntObject為整數類型
2.聲明一個整數後得到整數對象
3.對象ob_type指向PyInt_type對象
到這裏, 總結下
1.一切都是對象
2.PyType_Type/PyInt_Type/PyString_Type....等
這些是`類型對象`,可以認為是同級,都是PyTypeObject這種`類型`的實例!
3.雖然是同級,
但是其他PyXXX_Type,其類型指向PyType_Type
PyType_Type的類型指向自己,它是所有類型的`類型`
4.PyTypeObject是一個變長對象
5.每個object,例如PyIntObject都屬於一種`類型`
object初始化時進行關聯
多態是如何實現的?
對象的多態, 例如hash
>>>hash(1)
1
>>>hash("abc")
從上麵數據結構可以看到, 方法及屬性, 在不同Type實例化時就確定了
PyTypeObjectPyInt_Type={
...
(hashfunc)int_hash,/* tp_hash */
...
}
PyTypeObjectPyString_Type={
...
(hashfunc)string_hash,/* tp_hash */
...
}
Python內部傳遞的是泛型指針PyObject *, 函數調用時, 找到其類型* ob_type, 然後調用
object -> ob_type -> tp_hash
即: 大量函數指針決定了該類型的具體行為
來源:wklken
編輯 | 碼哥
圖片源於網絡,版權歸原作者所有
最後更新:2017-10-09 00:53:52