使用到的源代码文件

如何创建一个变量

程序的变量是计算机的存储单元或者对一系列存储单元的抽象。程序人员通常认为变量是存储地址的名字,但是变量的意义远大于此。我们通过用名字来代替变量在内存中的绝对地址,让我们避免了和地址直接打交道。

事实上一个变量可以用以下六个属性来刻画:
- 名字 - 变量名称
- 地址 - 内存中的存放地址
- - 变量值
- 类型 - 变量类型
- 生存期 - 变量生命周期
- 作用域 - 变量的可见性


PyIntObject和PyInt_Type

PyIntObject -用来表示一个整数

//[intobject.h]
typedef struct {
    PyObject_HEAD
    long ob_ival;
} PyIntObject;

PyAPI_DATA(PyTypeObject) PyInt_Type;

PyInt_Type - 用来表明一个整数对象的类型

PyTypeObject PyInt_Type = {
    PyObject_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_repr,         /* tp_repr */
    &int_as_number,             /* tp_as_number */
    0,                  /* tp_as_sequence */
    0,                  /* tp_as_mapping */
    (hashfunc)int_hash,         /* tp_hash */
        0,                  /* tp_call */
        (reprfunc)int_repr,         /* tp_str */
    PyObject_GenericGetAttr,        /* tp_getattro */
    0,                  /* tp_setattro */
    0,                  /* tp_as_buffer */
    Py_TPFLAGS_DEFAULT | Py_TPFLAGS_CHECKTYPES |
        Py_TPFLAGS_BASETYPE,        /* tp_flags */
    int_doc,                /* tp_doc */
    0,                  /* tp_traverse */
    0,                  /* tp_clear */
    0,                  /* tp_richcompare */
    0,                  /* tp_weaklistoffset */
    0,                  /* tp_iter */
    0,                  /* tp_iternext */
    int_methods,                /* tp_methods */
    0,                  /* tp_members */
    0,                  /* tp_getset */
    0,                  /* tp_base */
    0,                  /* tp_dict */
    0,                  /* tp_descr_get */
    0,                  /* tp_descr_set */
    0,                  /* tp_dictoffset */
    0,                  /* tp_init */
    0,                  /* tp_alloc */
    int_new,                /* tp_new */
    (freefunc)int_free,                 /* tp_free */
};

Python解决方案

Python几乎所有的对象都被维护在堆中,所以,会经常频繁地使用malloc家族的函数来分配/释放堆中的空间。如果我们每使用一个整数就去调用函数,分配内存,未免太过频繁,效率太低。
所以,Python使用了整数对象池来维护整数。

整数对象池

#define BLOCK_SIZE 1000    /* 1K less typical malloc overhead */
#define BHEAD_SIZE 8   /* Enough for a 64-bit pointer */
#define N_INTOBJECTS   ((BLOCK_SIZE - BHEAD_SIZE) / sizeof(PyIntObject))

struct _intblock {
    struct _intblock *next;
    PyIntObject objects[N_INTOBJECTS];
};

typedef struct _intblock PyIntBlock;

static PyIntBlock *block_list = NULL;
static PyIntObject *free_list = NULL;

综上,整数对象池在内存中的表示应该为:

接下来,我们看如何使用它们。

如何使用

Python把整数体系又分为了小整数和大整数。

首先,我们来看小整数。

intobject.c文件中,有以下几行代码:

#ifndef NSMALLPOSINTS
#define NSMALLPOSINTS      257
#endif
#ifndef NSMALLNEGINTS
#define NSMALLNEGINTS      5
#endif
#if NSMALLNEGINTS + NSMALLPOSINTS > 0
/* References to small integers are saved in this array so that they
   can be shared.
   The integers that are saved are those in the range
   -NSMALLNEGINTS (inclusive) to NSMALLPOSINTS (not inclusive).
*/
static PyIntObject *small_ints[NSMALLNEGINTS + NSMALLPOSINTS];
#endif

我们来剖析一下:

特别需要注意的是这里使用的是指针数组,真正的整数对象空间还没有被分配。

那么,这个small_int中的指针,都指向哪里了呢?答案是PyIntBlock
intobject.c中有如下一段代码,表明了小整数体系是如何被分配的:

int
_PyInt_Init(void)
{
    PyIntObject *v;
    int ival;
#if NSMALLNEGINTS + NSMALLPOSINTS > 0
    for (ival = -NSMALLNEGINTS; ival < NSMALLPOSINTS; ival++) {
              if (!free_list && (free_list = fill_free_list()) == NULL)
            return 0;
        /* PyObject_New is inlined */
        v = free_list;
        free_list = (PyIntObject *)v->ob_type;
        PyObject_INIT(v, &PyInt_Type);
        v->ob_ival = ival;
        small_ints[ival + NSMALLNEGINTS] = v;
    }
#endif
    return 1;
}

这里我们还使用到了函数fill_free_list():

static PyIntObject *
fill_free_list(void)
{
    PyIntObject *p, *q;
    /* Python's object allocator isn't appropriate for large blocks. */
    p = (PyIntObject *) PyMem_MALLOC(sizeof(PyIntBlock));
    if (p == NULL)
        return (PyIntObject *) PyErr_NoMemory();
    ((PyIntBlock *)p)->next = block_list;
    block_list = (PyIntBlock *)p;
    /* Link the int objects together, from rear to front, then return
       the address of the last int object in the block. */
    p = &((PyIntBlock *)p)->objects[0];
    q = p + N_INTOBJECTS;
    while (--q > p)
        q->ob_type = (struct _typeobject *)(q-1);
    q->ob_type = NULL;
    return p + N_INTOBJECTS - 1;
}

fill_free_list()每执行一次会申请一个block,我们可以画出申请结束后一个block的状态:

82个PyIntObject暂时使用ob_type指针连接成一个单向链表。
free_list是一个全局静态变量,指针类型,指向目前可用的PyIntObject

小整数系统就是也使用了这个单向链表来实现:

当然,如果你想创建一个整数,可以使用下面的函数(如果是小整数,就用small_ints,如果是大整数,直接分配对应的内存块):

PyObject *
PyInt_FromLong(long ival)
{
    register PyIntObject *v;
#if NSMALLNEGINTS + NSMALLPOSINTS > 0
    if (-NSMALLNEGINTS <= ival && ival < NSMALLPOSINTS) {
        v = small_ints[ival + NSMALLNEGINTS];
        Py_INCREF(v);
#ifdef COUNT_ALLOCS
        if (ival >= 0)
            quick_int_allocs++;
        else
            quick_neg_int_allocs++;
#endif
        return (PyObject *) v;
    }
#endif
    if (free_list == NULL) {
        if ((free_list = fill_free_list()) == NULL)
            return NULL;
    }
    /* Inline PyObject_New */
    v = free_list;
    free_list = (PyIntObject *)v->ob_type;
    PyObject_INIT(v, &PyInt_Type);
    v->ob_ival = ival;
    return (PyObject *) v;
}

整数可以使用的方法

使用dir()函数,可以看到整数可以使用的方法:

static PyNumberMethods 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_pos, /*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*/
    0,          /*nb_inplace_multiply*/
    0,          /*nb_inplace_divide*/
    0,          /*nb_inplace_remainder*/
    0,          /*nb_inplace_power*/
    0,          /*nb_inplace_lshift*/
    0,          /*nb_inplace_rshift*/
    0,          /*nb_inplace_and*/
    0,          /*nb_inplace_xor*/
    0,          /*nb_inplace_or*/
    (binaryfunc)int_div,    /* nb_floor_divide */
    int_true_divide,    /* nb_true_divide */
    0,          /* nb_inplace_floor_divide */
    0,          /* nb_inplace_true_divide */
    (unaryfunc)int_int, /* nb_index */
};

拿整数加法举例:

static PyObject *
int_add(PyIntObject *v, PyIntObject *w)
{
    register long a, b, x;
    CONVERT_TO_LONG(v, a);
    CONVERT_TO_LONG(w, b);
    x = a + b;
    if ((x^a) >= 0 || (x^b) >= 0)
        return PyInt_FromLong(x);
    return PyLong_Type.tp_as_number->nb_add((PyObject *)v, (PyObject *)w);
}

最后,注意object.c中的函数PyObject_Init()

PyObject *
PyObject_Init(PyObject *op, PyTypeObject *tp)
{
    if (op == NULL)
        return PyErr_NoMemory();
    /* Any changes should be reflected in PyObject_INIT (objimpl.h) */
    op->ob_type = tp;
    _Py_NewReference(op);
    return op;
}

总结

评论已关闭。

X