工作整兩年了遗座,用python最多馋记,然而對(duì)于python內(nèi)部機(jī)制不一定都清楚,每天沉醉于增刪改查的簡(jiǎn)單邏輯編寫(xiě),實(shí)在耗神。很多東西不用就忘記了,比如C語(yǔ)言驾茴,正好,python源碼用C寫(xiě)的,分析python源碼的同時(shí)又能溫故C語(yǔ)言基礎(chǔ),實(shí)在是件很好的事情。另外,還有陳儒大神的《python源碼剖析》做指引挥转,分析也不至于沒(méi)頭沒(méi)腦。期望在一個(gè)月的業(yè)余時(shí)間豁护,能有所小成班缎,以此為記沉唠。
1 python中的對(duì)象
python中乳蛾,一切東西都是對(duì)象因惭,在c語(yǔ)言實(shí)現(xiàn)中對(duì)應(yīng)著結(jié)構(gòu)體。首先當(dāng)然還是從python內(nèi)建對(duì)象開(kāi)始看起,最基本的是PyIntObject, PyStringObject, PyListObject, PyDictObject這幾個(gè)讳推,他們分別屬于int,string, list, dict類(lèi)型设拟。從python2.2之后有了new style class之后帘撰,這些內(nèi)置對(duì)象都是繼承自object類(lèi)型核行,object在代碼中對(duì)應(yīng)PyBaseObject_Type惩系。比如我們賦值語(yǔ)句a=3擦剑,那么a就是一個(gè)PyIntObject對(duì)象,它的類(lèi)型是int,在代碼中對(duì)應(yīng)PyInt_Type炫乓,PyInt_Type也是一種對(duì)象末捣,我們稱(chēng)之為類(lèi)型對(duì)象侠姑。那么PyInt_Type它的類(lèi)型是什么呢,答案是type箩做, 對(duì)應(yīng)到代碼中就是PyType_Type莽红。當(dāng)然object也是一個(gè)類(lèi)型對(duì)象,它的類(lèi)型也是PyType_Type邦邦。這么一層層下去安吁,PyType_Type也是個(gè)對(duì)象,那它的類(lèi)型又是什么呢燃辖,沒(méi)錯(cuò)鬼店,答案就是它的類(lèi)型就是它自己,黔龟「局牵看下面的驗(yàn)證代碼:
##內(nèi)建對(duì)象測(cè)試
In [1]: a = 3
In [2]: type(a)
Out[2]: int
In [3]: type(int)
Out[3]: type
In [4]: type(type)
Out[4]: type
In [5]: int.__base__
Out[5]: object
In [6]: type(object)
Out[6]: type
先分析下幾個(gè)基礎(chǔ)內(nèi)建對(duì)象在C語(yǔ)言中的結(jié)構(gòu)體以及常用的幾個(gè)宏确沸,為了方便,我用的也是陳儒大神分析的那個(gè)版本一致俘陷,版本是2.5.6.源碼官網(wǎng)有下載罗捎。
// 內(nèi)建對(duì)象基礎(chǔ)
#define PyObject_HEAD \
Py_ssize_t ob_refcnt; \
struct _typeobject *ob_type;
#define PyObject_HEAD_INIT(type) \
1, type,
#define PyObject_VAR_HEAD \
PyObject_HEAD \
Py_ssize_t ob_size; /* Number of items in variable part */
#define Py_INVALID_SIZE (Py_ssize_t)-1
typedef struct _object {
PyObject_HEAD
} PyObject;
typedef struct {
PyObject_VAR_HEAD
} PyVarObject;
typedef struct _typeobject {
PyObject_VAR_HEAD
const char *tp_name; /* For printing, in format "<module>.<name>" */
Py_ssize_t tp_basicsize, tp_itemsize; /* For allocation */
destructor tp_dealloc;
printfunc tp_print;
getattrfunc tp_getattr;
setattrfunc tp_setattr;
cmpfunc tp_compare;
reprfunc tp_repr;
...
} PyTypeObject;
typedef struct {
PyObject_HEAD
long ob_ival;
} PyIntObject;
typedef struct {
PyObject_VAR_HEAD
long ob_shash;
int ob_sstate;
char ob_sval[1];
/* Invariants:
* ob_sval contains space for 'ob_size+1' elements.
* ob_sval[ob_size] == 0.
* ob_shash is the hash of the string or -1 if not computed yet.
* ob_sstate != 0 iff the string object is in stringobject.c's
* 'interned' dictionary; in this case the two references
* from 'interned' to this object are *not counted* in ob_refcnt.
*/
} PyStringObject;
如代碼中所示,PyObject是所有Python對(duì)象的基石拉盾,所有后續(xù)看到的對(duì)象都有一個(gè)相同的PyObject頭部,從而我們可以在源碼中看到所有的對(duì)象都可以用PyObject指針指向桨菜,這就是面向?qū)ο笾薪?jīng)常用到的多態(tài)的技巧了。Python內(nèi)部各個(gè)函數(shù)對(duì)象間也是通過(guò)PyObject傳遞捉偏,即便本身這是一個(gè)PyIntObject類(lèi)型的對(duì)象倒得,代碼中并不會(huì)用PyIntObject*指針進(jìn)行傳遞,這也是為了實(shí)現(xiàn)多態(tài)夭禽。比如下面的函數(shù):
void Print(PyObject* object) {
object->ob_type->tp_print(object);
}
另外如代碼中注釋所說(shuō)的霞掺,變長(zhǎng)對(duì)象的ob_size指的是元素個(gè)數(shù),不是字節(jié)數(shù)目讹躯。
2 python對(duì)象引用計(jì)數(shù)
下面是幾個(gè)常用的操作對(duì)象引用計(jì)數(shù)的宏定義(object.h)菩彬,一并列出,這里去除了一些調(diào)試時(shí)用的代碼潮梯,更容易看明白代碼含義骗灶。Py_NewReference是初始化時(shí)對(duì)象時(shí)設(shè)置引用計(jì)數(shù), Py_INCREF和Py_DECREF分別用來(lái)增加引用技術(shù)和減少引用計(jì)數(shù)。從代碼中可以看到秉馏,python增加引用和減少引用都是通過(guò)這些宏操作的耙旦,**有一點(diǎn)需要注意的是,當(dāng)對(duì)象引用ob_refcnt減小到0時(shí)萝究,會(huì)調(diào)用對(duì)象的析構(gòu)函數(shù)免都,析構(gòu)函數(shù)并不一定會(huì)調(diào)用free釋放內(nèi)存空間,因?yàn)轭l繁申請(qǐng)和釋放內(nèi)存嚴(yán)重影響性能帆竹,所以在后面看到python有大量用到內(nèi)存池技術(shù)绕娘,對(duì)提升性能有很大效果。
需要說(shuō)明的是馆揉,類(lèi)型對(duì)象是不在引用計(jì)數(shù)規(guī)則之中的业舍,每個(gè)對(duì)象指向類(lèi)型對(duì)象的指針并不視為類(lèi)型對(duì)象的引用,也就是說(shuō)不會(huì)影響類(lèi)型對(duì)象的引用計(jì)數(shù)升酣,類(lèi)型對(duì)象永遠(yuǎn)不會(huì)被析構(gòu)舷暮。
#define _Py_NewReference(op) ((op)->ob_refcnt = 1)
#define _Py_Dealloc(op) (*(op)->ob_type->tp_dealloc)((PyObject *)(op)))
#define Py_INCREF(op) ((op)->ob_refcnt++)
#define Py_DECREF(op) \
if (--(op)->ob_refcnt != 0) \
;
else \
_Py_Dealloc((PyObject *)(op))
#define Py_CLEAR(op) \
do { \
if (op) { \
PyObject *tmp = (PyObject *)(op); \
(op) = NULL; \
Py_DECREF(tmp); \
} \
} while (0)
/* Macros to use in case the object pointer may be NULL: */
#define Py_XINCREF(op) if ((op) == NULL) ; else Py_INCREF(op)
#define Py_XDECREF(op) if ((op) == NULL) ; else Py_DECREF(op)
3 Python對(duì)象分類(lèi)
python中的對(duì)象大致可以分為下面幾類(lèi):
- 數(shù)值對(duì)象:如integer,float,boolean
- 序列集合對(duì)象:如string,list,tuple
- 字典對(duì)象:如dict
- 類(lèi)型對(duì)象:如type
- 內(nèi)部對(duì)象:如后面會(huì)看到的code,function噩茄,frame下面,module以及method對(duì)象等。
4 參考資料
- 《python源碼剖析》