Ec87adf72e8cfd93d9c66ba7aa5ee7b0
Python 的整数设计

Python的整数设计

上一次我们在讲解Python的对象、类的设计的时候,举了大量PyIntObject类型的例子。其实PyIntObject就是我们通常理解的int数据类型。在许多编程语言中,int都是一些基础数据类型(比如C, Objective-C),基础数据类型都是由编译器制定和提供。而在Python中,由于其万物皆对象的设计理念,自建了数据类型PyIntObject。因此,在这一部分我们一起来探究下Python是如何设计int类型以及如何解决由于转变成对象后带来的内存及性能问题。

类型定义

[intobject.h/.c]文件中,我们可以比较清晰的看出PyIntObject的定义结构:

typedef struct {
    PyObject_HEAD
    long ob_ival;
} PyIntObject;

换句话说,除了对象头部的类型指针及引用计数(简化版),只有一个编译器提供了long类型用来存储真正的整数数据。

好,除此之外,我们还要记得PyIntObject对象的类型对象,即创建整数对象的描述符PyInt_Type,通过它,我们能知道这个类占用的内存大小、构造函数、析构函数能一些元信息,具体如下:

PyTypeObject PyInt_Type = {
    PyVarObject_HEAD_INIT(&PyType_Type, 0)
    "int",
    sizeof(PyIntObject),
    0,
    (destructor)int_dealloc,                    /* tp_dealloc */
    (printfunc)int_print,                       /* tp_print */
    0,                                          /* tp_getattr */
    0,                                          /* tp_setattr */
    (cmpfunc)int_compare,                       /* tp_compare */
    (reprfunc)int_to_decimal_string,            /* tp_repr */
    &int_as_number,                             /* tp_as_number */
    0,                                          /* tp_as_sequence */
    0,                                          /* tp_as_mapping */
    (hashfunc)int_hash,  

    ... 省略篇幅
}

不难看出,就是一堆定义的函数指针,指向了PyIntObject对象所需要的行为方法,比如int_compare,该方法定义了如何比较两个PyIntObject对象的大小,具体如下:

static int
int_compare(PyIntObject *v, PyIntObject *w)
{
    register long i = v->ob_ival;
    register long j = w->ob_ival;
    return (i < j) ? -1 : (i > j) ? 1 : 0;
}

实现非常直观易懂,不再赘述。

绝大多数情况下register关键字没什么用。

方法簇

前面我们提到了,在诸如C这样的语言中,整数类型是由编译器提供的。因此,对int操作加减乘除等运算的时候,最后都会转换成对应的机器码。以加法举例 a = a + 1,对应的汇编助记符可能如下:

mov x1, 1
add x0, x1

那么在Python中,由于对象的类型是自行设计的,我们如何让其支持这些运算操作呢?

答案就在方法簇这个设计上

我们重点关注下int_as_number这个结构,如果不仔细辨别,第一眼你可能认为他还是个函数指针,但是实质上,他是一个函数指针数组

static PyNumberMethods int_as_number = {
    (binaryfunc)int_add,        /*nb_add*/
    (binaryfunc)int_sub,        /*nb_subtract*/
    (binaryfunc)int_mul,        /*nb_multiply*/
    (binaryfunc)int_classic_div, /*nb_divide*/
    (binaryfunc)int_mod,        /*nb_remainder*/
    (binaryfunc)int_divmod,     /*nb_divmod*/
    (ternaryfunc)int_pow,       /*nb_power*/
    (unaryfunc)int_neg,         /*nb_negative*/
    (unaryfunc)int_int,         /*nb_positive*/
    (unaryfunc)int_abs,         /*nb_absolute*/
    (inquiry)int_nonzero,       /*nb_nonzero*/
    (unaryfunc)int_invert,      /*nb_invert*/
    (binaryfunc)int_lshift,     /*nb_lshift*/
    (binaryfunc)int_rshift,     /*nb_rshift*/
    (binaryfunc)int_and,        /*nb_and*/
    (binaryfunc)int_xor,        /*nb_xor*/
    (binaryfunc)int_or,         /*nb_or*/
    int_coerce,                 /*nb_coerce*/
    (unaryfunc)int_int,         /*nb_int*/
    (unaryfunc)int_long,        /*nb_long*/
    (unaryfunc)int_float,       /*nb_float*/
    (unaryfunc)int_oct,         /*nb_oct*/
    (unaryfunc)int_hex,         /*nb_hex*/
    0,                          /*nb_inplace_add*/
    0,                          /*nb_inplace_subtract*/
top Created with Sketch.