Python进阶编程:编写更高效、优雅的Python代码
上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个函数族中的所有操作。换句话说,一个对象可以既表现出数值对象的特性,也可以表现出关联对象的特性。