【Python】整数

2018-10-26  本文已影响10人  lndyzwdxhs

0x01 PyIntObject

typedef struct {
    PyObject_HEAD
    long ob_ival;
} PyIntObject;

PyIntObject对象表示一个整数(long类型的)。它是一个不可变对象,一旦创建了以后,值不能被改变。

整数是非常常见的对象。使用奇数指针表示整数可以节省很多空间,但是在特殊情况下需要贯穿整个代码来检查(Using odd pointers to represent integers would save much space but require extra checks for this special case throughout the code)。

由于一个典型的python程序需要使用很多次整数,所以就要申请和释放内存很多次,这个过程理应是非常快的。因此我们使用具有很低开销的专门的内存分配方案,而不是直接使用malloc():一个简单的专用空闲列表,在需要的时候申请内存填充这个列表。

block_list是所有PyIntBlocks对象(all PyIntBlocks)组成的单向链表,PyIntBlocks是之前申请的内存结构,链表通过节点的下一个成员连接(linked via their next members)。PyIntBlocks在系统结束(shutdown)的时候会返回给操作系统。

free_list是可以使用的PyIntObjects对象(available PyIntObjects)组成的单向链表,通过ob_type成员的滥用来连接这个链表(linked via abuse of their ob_type members)。

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函数实现图解
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;
}

// test demon:
// test.c 
#include <stdlib.h>
#include <stdio.h>
#define NSMALLNEGINTS 5
#define NSMALLPOSINTS 257
int small_ints[NSMALLNEGINTS + NSMALLPOSINTS];

int main()
{
    int ival;
    for(ival=-NSMALLNEGINTS; ival < NSMALLPOSINTS; ival++){
        small_ints[ival + NSMALLNEGINTS] = ival;
    }
    for(int i=0; i<NSMALLNEGINTS + NSMALLPOSINTS; i++){
        printf("index:%d, value:%d\n", i, small_ints[i]);
    }
    return 0;
}

// 执行结果:
// ./test 
index:0, value:-5
index:1, value:-4
index:2, value:-3
index:3, value:-2
index:4, value:-1
index:5, value:0
index:6, value:1
index:7, value:2
index:8, value:3
index:9, value:4
index:10, value:5
index:11, value:6
index:12, value:7
......
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 *)Py_TYPE(v);
    (void)PyObject_INIT(v, &PyInt_Type);
    v->ob_ival = ival;
    return (PyObject *) v;
}

欢迎关注微信公众号(coder0x00)或扫描下方二维码关注,我们将持续搜寻程序员必备基础技能包提供给大家。


上一篇 下一篇

猜你喜欢

热点阅读