`
tomhibolu
  • 浏览: 1383233 次
文章分类
社区版块
存档分类
最新评论

[Python源码学习]之整数类型PyIntObject

 
阅读更多

在Python2中,有 PyIntObject 和 PyLongObject 两种整数类型,在Python3中,前者并入后者。本文是Python2 相关的内容。

PyIntObject

整数对象定义在头文件 Include/intobject.h 中,它表示一个(长)整数,且是一个不可变(immutable)对象。

typedef struct {
    PyObject_HEAD
    long ob_ival;
} PyIntObject;

和PyObject相比,它只多了一个 ob_ival 成员,用来封装C中的long类型。

PyIntObject 的类型值是: PyInt_Type,定义在 Objects/intobject.c 中

PyInt_Type

定义在 Objects/intobject.cpp 中,且在 Include/intobject.h 中用 extern 进行声明。

  • Include/intobject.h

PyAPI_DATA(PyTypeObject) PyInt_Type;
  • 注:PyAPI_DATA是一个宏,定义在 Include/pyport.h 中,用来隐藏动态库时平台的差异,片段如下:
    ...
    #define PyAPI_FUNC(RTYPE) __declspec(dllexport) RTYPE
    #define PyAPI_DATA(RTYPE) extern __declspec(dllexport) RTYPE
    ...
  • Objects/intobject.c

PyTypeObject PyInt_Type = {
    PyVarObject_HEAD_INIT(&PyType_Type, 0)
    "int",
    sizeof(PyIntObject),
...                                       
    (cmpfunc)int_compare,                       /* tp_compare */
    (reprfunc)int_to_decimal_string,            /* tp_repr */
    &int_as_number,                             /* tp_as_number */
...                                        
    (reprfunc)int_to_decimal_string,            /* tp_str */
...
    Py_TPFLAGS_DEFAULT | Py_TPFLAGS_CHECKTYPES |
        Py_TPFLAGS_BASETYPE | Py_TPFLAGS_INT_SUBCLASS,          /* tp_flags */
    int_doc,                                    /* tp_doc */
...
    int_new,                                    /* tp_new */
    (freefunc)int_free,                         /* tp_free */
};

宏 PyVarObject_HEAD_INIT 定义在 Include/object.h 中,用来初始化PyVarObject的3个成员(引用计数始终初始化为1)

PyNumberMethods

&int_as_number 是指向结构体PyNumberMethods实例的指针,该结构体的成员是函数指针:

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*/
...

这些函数实现了整数的四则运算等操作。比如加法

static PyObject *
int_add(PyIntObject *v, PyIntObject *w)
{
    register long a, b, x;
    CONVERT_TO_LONG(v, a);
    CONVERT_TO_LONG(w, b);
    /* casts in the line below avoid undefined behaviour on overflow */
    x = (long)((unsigned long)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);
}

返回结果是通过PyInt_FromLong创建的新对象。如果溢出的话,则调用PyLong_Type的加法函数。

创建

为了提高效率,某个范围内的小整数进行了缓存(是该称作缓存么?)。

小整数

缓存在一个静态的 small_ints 的数组中:

需要缓存的数据范围由两个宏进行指定(所以修改的话需要重新编译python)

#define NSMALLPOSINTS           257
#define NSMALLNEGINTS           5

/* 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];

大整数

大整数存放在PyIntBlock的一个单向链表中,每一个PyIntBlock项中可以存放若干个(N_INTOBJECTS)整数。

/*
   block_list is a singly-linked list of all PyIntBlocks ever allocated,
   linked via their next members.  PyIntBlocks are never returned to the
   system before shutdown (PyInt_Fini).

   free_list is a singly-linked list of available PyIntObjects, linked
   via abuse of their ob_type members.
*/

#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;

此处两个静态的指针,block_list 和 free_list 分别指向整数块(IntBlock)链表和空闲空间(IntObject)链表的头部。

有问题是不?PyIntBlock很容易看出是一个链表的节点,可是PyIntObject如何能是链表的节点呢?

它只有3个成员:

Py_ssize_t ob_refcnt;
struct _typeobject *ob_type;
long ob_ival;

哦,原来它使用的 ob_type 来存放下一个节点指针!!

这样以来,当新建整数时,首先判断是否是小整数,是的话,直接使用缓存中的小整数,反之,看看整数块有没有空闲的空间,有则使用,无则申请新的整数块。

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);
    PyObject_INIT(v, &PyInt_Type);
    v->ob_ival = ival;
    return (PyObject *) v;
}

PyInt_From*

整数的创建:

  • C的整数类型创建Python的整数对象

  • 字符串创建Python的整数对象

PyObject * PyInt_FromLong(long ival)
PyObject * PyInt_FromSize_t(size_t ival)
PyObject * PyInt_FromSsize_t(Py_ssize_t ival)
PyObject * PyInt_FromString(char *s, char **pend, int base)
PyObject * PyInt_FromUnicode(Py_UNICODE *s, Py_ssize_t length, int base)

参考


分享到:
评论

相关推荐

    Python源码剖析

    Python源码剖析 首页 Python总体架构 对象机制 字符串对象PyStringObject(1) 字符串对象PyStringObject(2) 字符串对象PyStringObject(3) 整数对象PyIntObject(1) 整数对象PyIntObject(2) 整数对象PyIntObject(3) ...

    Python BBS论坛源码 Python源码

    Python BBS论坛源码 Python源码Python BBS论坛源码 Python源码Python BBS论坛源码 Python源码Python BBS论坛源码 Python源码Python BBS论坛源码 Python源码Python BBS论坛源码 Python源码Python BBS论坛源码 Python...

    Python源码剖析.pdf

    Python源码剖析.pdf

    Python Excel数据分析 Python源码

    Python Excel数据分析 Python源码Python Excel数据分析 Python源码Python Excel数据分析 Python源码Python Excel数据分析 Python源码Python Excel数据分析 Python源码Python Excel数据分析 Python源码Python Excel...

    圣诞树代码编程python源码附赠30个Python应用源码.rar

    圣诞树代码编程python源码附赠30个Python应用源码圣诞树代码编程python源码附赠30个Python应用源码圣诞树代码编程python源码附赠30个Python应用源码圣诞树代码编程python源码附赠30个Python应用源码圣诞树代码编程...

    玫瑰花python源码.zip

    玫瑰花python源码.zip玫瑰花python源码.zip玫瑰花python源码.zip玫瑰花python源码.zip玫瑰花python源码.zip玫瑰花python源码.zip玫瑰花python源码.zip玫瑰花python源码.zip玫瑰花python源码.zip玫瑰花python源码.zip...

    Python源码学习笔记.zip

    Python源码学习笔记

    Python 笔记源码——内含python后端&机器学习等.zip

    Python 笔记源码——内含python后端&机器学习等.zip Python 笔记源码——内含python后端&机器学习等.zip Python 笔记源码——内含python后端&机器学习等.zip Python 笔记源码——内含python后端&机器学习等.zip ...

    Python 游戏源码 - 飞鸟小游戏 Python源码

    Python 游戏源码 - 飞鸟小游戏 Python源码Python 游戏源码 - 飞鸟小游戏 Python源码Python 游戏源码 - 飞鸟小游戏 Python源码Python 游戏源码 - 飞鸟小游戏 Python源码Python 游戏源码 - 飞鸟小游戏 Python源码...

    Python 如何自动对多个Word文档提取目录 Python源码

    Python 如何自动对多个Word文档提取目录 Python源码Python 如何自动对多个Word文档提取目录 Python源码Python 如何自动对多个Word文档提取目录 Python源码Python 如何自动对多个Word文档提取目录 Python源码Python ...

    Golang和Python源码学习.zip

    Golang和Python源码学习

    Python 读取Excel、文本、CSV等不同类型数据 Python源码

    Python 读取Excel、文本、CSV等不同类型数据 Python源码Python 读取Excel、文本、CSV等不同类型数据 Python源码Python 读取Excel、文本、CSV等不同类型数据 Python源码Python 读取Excel、文本、CSV等不同类型数据 ...

    Python源码剖析笔记

    python源码剖析笔记 python源码剖析笔记 python源码剖析笔记

    Python 如何实现在PyQt5窗口中弹出等待提示框 Python源码

    Python 如何实现在PyQt5窗口中弹出等待提示框 Python源码Python 如何实现在PyQt5窗口中弹出等待提示框 Python源码Python 如何实现在PyQt5窗口中弹出等待提示框 Python源码Python 如何实现在PyQt5窗口中弹出等待提示...

    Python 重复数据处理(df.drop-duplicates方法)Python源码

    Python 重复数据处理(df.drop_duplicates方法)Python源码Python 重复数据处理(df.drop_duplicates方法)Python源码Python 重复数据处理(df.drop_duplicates方法)Python源码Python 重复数据处理(df.drop_...

    Python 商城源码 Python源码

    Python 商城源码 Python源码Python 商城源码 Python源码Python 商城源码 Python源码Python 商城源码 Python源码Python 商城源码 Python源码Python 商城源码 Python源码Python 商城源码 Python源码Python 商城源码 ...

    基于机器学习的电影推荐系统python源码+数据集(下载即用).zip

    基于机器学习的电影推荐系统python源码+数据集(下载即用).zip基于机器学习的电影推荐系统python源码+数据集(下载即用).zip基于机器学习的电影推荐系统python源码+数据集(下载即用).zip基于机器学习的电影推荐系统...

    python三剑客源码

    python 源码 三剑客“python编程从入门到实践、python极客编程、python编程快速上手”。python 源码 三剑客“python编程从入门到实践、python极客编程、python编程快速上手”python 源码 三剑客“python编程从...

Global site tag (gtag.js) - Google Analytics