上QQ阅读APP看书,第一时间看更新
0.3.8 对象的行为
PyTypeObject中定义了大量的函数指针。这些函数指针可以视为类型对象中所定义的操作,这些操作直接决定着对象在运行时所表现出的行为,比如PyTypeObject中的tp_hash指明了该类型对象如何生成其hash值。
在PyTypeObject的源码中,可以看到非常重要的3组操作族:PyNumberMethods*tp_as_number、PySequenceMethods*tp_as_sequence、PyMappingMethods*tp_as_mapping。
PyNumberMethods的源码(Include/object.h)如下:
// Include/object.h typedef PyObject * (*binaryfunc)(PyObject *, PyObject *); typedef struct { binaryfunc nb_matrix_multiply; binaryfunc nb_inplace_matrix_multiply; ...... } PyNumberMethods;
PyNumberMethods定义了数值对象该支持的操作。数值对象如果是整数对象,那么它的类型对象PyLong_Type中的tp_as_number.nb_add就指定了其进行加法操作时的具体行为。
在以下源码中,我们可以看出PyLong_Type中的tp_as_number指向的是long_as_number:
// Objects/longobject.c static PyNumberMethods long_as_number = { (binaryfunc)long_add, /*nb_add*/ (binaryfunc)long_sub, /*nb_subtract*/ (binaryfunc)long_mul, /*nb_multiply*/ ...... }; PyTypeObject PyLong_Type = { PyVarObject_HEAD_INIT(&PyType_Type, 0) "int", /* tp_name */ offsetof(PyLongObject, ob_digit), /* tp_basicsize */ sizeof(digit), /* tp_itemsize */ long_dealloc, /* tp_dealloc */ 0, /* tp_print */ 0, /* tp_getattr */ 0, /* tp_setattr */ 0, /* tp_reserved */ long_to_decimal_string, /* tp_repr */ &long_as_number, /* tp_as_number */ 0, /* tp_as_sequence */ 0, /* tp_as_mapping */ ...... };
PySequenceMethods和PyMappingMethods的分析与PyNumberMethods相同,分别定义了作为序列对象和关联对象应该支持的行为。这两种对象的典型例子是list和dict,大家可以自行查阅源码。
一种类型可以同时定义3个函数族中的所有操作。换句话说,一个对象可以既表现出数值对象的特性,也可以表现出关联对象的特性。