这几天在看《Python源码剖析》一书,一路看来总感觉讲得挺清楚的,绝对是一本好书。可是看到第十二章的“从type对象到class对象”时就感觉一直看不懂。遂google之,未果。于是自己看源码。
感觉在看关于slot的时候迷迷糊糊的,又突然冒出个PyHeapTypeObject,这有什么用?
首先,从typeobject.c的PyType_Ready函数看起,进入add_operators(type)函数。里面主要调用了init_
slotdefs
(),在init_slotdefs()中,它对static slotdefs数组进行排序,里面主要调用了C库函数qsort (
void qsort ( void * base, size_t num, size_t size, int ( * comparator ) ( const void *, const void * ) );
),该函数的排序利用了slotdef的offset项。
之后利用各slotdef项的offset定位PyHeapTypeObject中的相对应的操作,赋给ptr,之后跳过一系列错误处理,就到了PyDescr_NewWrapper
(),在该函数中新建了一个PyWrapperDescr_Type对象,并将它的d_base指向了刚才获取的ptr(PyHeapTypeObject中相对应的处理函数),以及将d_base指向了slotdef
descr->d_base = base;
descr->d_wrapped = wrapped;
之后便将该tuple插入了tp_dict。
到此,完成了275页图12-8的下半部分。
为了可以匹配上那张图,我打开了listobject.c文件,找到了其中的tp_as_mapping域,该值为&list_as_mapping,是一个PyMappingMethods类型:
static PyMappingMethods list_as_mapping = {
(lenfunc)list_length,
(binaryfunc)list_subscript,
(objobjargproc)list_ass_subscript
};
它所指的正是图中标出的list_subscript!其中的各个域都是在该文件中实现的函数
另外,在对slotdefs数组进行初始化时,其中定义了许多宏:
#define MPSLOT(NAME, SLOT, FUNCTION, WRAPPER, DOC) \
ETSLOT(NAME, as_mapping.SLOT, FUNCTION, WRAPPER, DOC)
#define ETSLOT(NAME, SLOT, FUNCTION, WRAPPER, DOC) \
{NAME, offsetof(PyHeapTypeObject, SLOT), (void *)(FUNCTION), WRAPPER, \
PyDoc_STR(DOC)}
以上的宏在初始化slotdefs中有:
MPSLOT("__getitem__", mp_subscript, slot_mp_subscript,
wrap_binaryfunc,
"x.__getitem__(y) <==> x[y]"),
通过其中的MPSLOT以及ETSLOT宏找到其中的操作操作相对于PyHeapTypeObject的偏移,从而将值存储到了slotdef的offset处
这样,之前通过该offset所取得的函数就可以通过该offset重新获取该函数,顺便可以利用offset的大小进行排序。所以,从这里来看,PyHeapTypeObject可以看作是一块大的函数指针聚集。它的第一项可以容纳任何类型的PyObject对象,它主要用于class的创建,初始化时将各种方法什么的统一放到它的下面的域中,可以看作是对一个PyObject对象的暂时的包装。