二、整数对象

1、PyIntObject

2、PyIntObject 对象的创建和维护

3、Hack PyIntObject


1、PyIntObject

PyIntObject的定义:

[intobject.h]

typedef struct {

PyObject_HEAD

long ob_ival;

} PyIntObject;

其类型对象为PyInt_Type:

[intobject.c]

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

};

可见PyInt_Type保存着PyIntObject的元信息,包括这些操作:

int_dealloc

删除PyIntObject对象

int_free

删除PyIntObject对象

int_repr

转化成PyString对象

int_hash

获得HASH值

int_print

打印PyIntObject对象

int_compare

比较操作

int_as_number

数值操作

int_methods

成员函数

比较操作代码,其实就是将包装的long进行比较:

[intobject.c]

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;

}

注意int_as_number,其实是一个PyNumberMethods结构体:

[intobject.c]

static PyNumberMethods int_as_number = {

(binaryfunc)int_add,    /*nb_add*/

(binaryfunc)int_sub,    /*nb_subtract*/

(binaryfunc)int_mul,    /*nb_multiply*/

……

(binaryfunc)int_div,    /* nb_floor_divide */

int_true_divide,    /* nb_true_divide */

0,          /* nb_inplace_floor_divide */

0,          /* nb_inplace_true_divide */

};

PyNumberMethods定义了38个数值操作,如加法:

[intobject.h]

/* Macro, trading safety for speed */

#define PyInt_AS_LONG(op) (((PyIntObject *)(op))->ob_ival)

[intobject.c]

#define CONVERT_TO_LONG(obj, lng)       \

if (PyInt_Check(obj)) {         \

lng = PyInt_AS_LONG(obj);   \

}                   \

else {                  \

Py_INCREF(Py_NotImplemented);   \

return Py_NotImplemented;   \

}

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

}

如果没有溢出,就返回一个新的PyIntObject,否则返回一个PyLongObject。


2、PyIntObject 对象的创建和维护

2.1、Python创建的途径

有三种途径可获得一个PyIntObject对象:

  PyObject *PyInt_FromLong(long ival)
  PyObject* PyInt_FromString(char *s, char **pend, int base)
#ifdef Py_USING_UNICODE
PyObject*PyInt_FromUnicode(Py_UNICODE *s, int length, int base)
#endif

其中PyInt_FromString时先转成浮点数再调用PyInt_FromLong:

[intobject.c]
PyObject* PyInt_FromString(char *s, char **pend, int base)
{
    char *end;
    long x;
    ......
//convert string to long
if (base == 0 && s[0] == '0') 
{
        x = (long) PyOS_strtoul(s, &end, base);
    }
else
        x = PyOS_strtol(s, &end, base);
    ......
    return PyInt_FromLong(x);
}

2.2、小整数对象

频繁申请、释放空间会降低运行效率、产生系统堆内存碎片,影响python性能。因此对于经常使用的整数,python使用对象池技术,并将小整数(对象池保存范围)定位[-5,100):

[intobject.c]

#ifndef NSMALLPOSINTS
#define NSMALLPOSINTS       100
#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

2.3、大整数对象

对于大整数,pyhton则是使用内存池,提供一个free_list保存,谁需要保存谁:

[intobject.c]

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

PyIntBlock的单向列表通过block_list维护,而这些block中的PyIntObject的列表中可以被使用的内存通过free_list来维护(一个block可放82个PyIntObject)。

2.4、添加和删除

看一下产生PyIntObject:

[intobject.c]
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;
}

先判断是否为小整数,是的话返回对象池中的小整数;否则转向block_list,调用fill_free_list:

[intobject.c]
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;
}

当一个block没被填满时,不会再调用fill_free_list申请新空间,free_list指向可用空间,block_list指向最新创建的PyIntBlock对象。

注意,但某个对象被删除时,free_list会指向该空间,不会造成空间浪费:

[intobject.c]
static void int_dealloc(PyIntObject *v)
{
    if (PyInt_CheckExact(v)) {
        v->ob_type = (struct _typeobject *)free_list;
        free_list = v;
    }
    else
        v->ob_type->tp_free((PyObject *)v);
}

2.5、小整数对象池的初始化

小整数对象池small_ints初始化 _PyInt_Init:

[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;
}

3、Hack PyIntObject

修改int_print源码查看block_list、free_list、小整数缓冲池信息:

static int int_print(PyIntObject *v, FILE *fp, int flags)

{

PyIntObject* intObjectPtr;

PyIntBlock *p = block_list;

PyIntBlock *last = NULL;

int count = 0;

int i;

while(p != NULL)

{

++count;

last = p;

p = p->next;

}

intObjectPtr = last->objects;

intObjectPtr += N_INTOBJECTS - 1;

printf("address @%p\n", v);

printf("********** value\trefCount **********\n");

for(i = 0; i < 10; ++i, --intObjectPtr)

{

printf("%d\t\t%d\n", intObjectPtr->ob_ival, intObjectPtr->ob_refcnt);

}

printf("block_list count : %d\n", count);

printf("free_list : %p\n\n", free_list);

return 0;

}

有兴趣的可以试一下。

Python 源码剖析(二)【整数对象】的更多相关文章

  1. 《Python 源码剖析》之对象

    py一切皆对象的实现 Python中对象分为两类: 定长(int等), 非定长(list/dict等) 所有对象都有一些相同的东西, 源码中定义为PyObject和PyVarObject, 两个定义都 ...

  2. Python源码剖析——01内建对象

    <Python源码剖析>笔记 第一章:对象初识 对象是Python中的核心概念,面向对象中的"类"和"对象"在Python中的概念都为对象,具体分为 ...

  3. Python 源码剖析(一)【python对象】

    处于研究python内存释放问题,在阅读部分python源码,顺便记录下所得.(基于<python源码剖析>(v2.4.1)与 python源码(v2.7.6)) 先列下总结:      ...

  4. Python开发【源码剖析】 List对象

    前言 本文探讨的Python版本为2.7.16,可从官网上下载,把压缩包Python-2.7.16.tgz解压到本地即可 需要基本C语言的知识(要看的懂) PyListObject对象 PyListO ...

  5. Python源码剖析——02虚拟机

    <Python源码剖析>笔记 第七章:编译结果 1.大概过程 运行一个Python程序会经历以下几个步骤: 由解释器对源文件(.py)进行编译,得到字节码(.pyc文件) 然后由虚拟机按照 ...

  6. python源码剖析学习记录-01

    学习<Python源码剖析-深度探索动态语言核心技术>教程         Python总体架构,运行流程   File Group: 1.Core Modules 内部模块,例如:imp ...

  7. Python源码剖析|百度网盘免费下载|Python新手入门|Python新手学习资料

    百度网盘免费下载:Python源码剖析|新手免费领取下载 提取码:g78z 目录  · · · · · · 第0章 Python源码剖析——编译Python0.1 Python总体架构0.2 Pyth ...

  8. Python 源码剖析 目录

    Python 源码剖析 作者: 陈儒 阅读者:春生 版本:python2.5 版本 本博客园的博客记录我会适当改成Python3版本 阅读 Python 源码剖析 对读者知识储备 1.C语言基础知识, ...

  9. [Python源码剖析]获取Python小整数集合范围

    #!/usr/bin/env python #-*- coding=utf-8 -*- small_ints = dict() for i in range(-10000,10000): small_ ...

  10. Python 源码剖析(六)【内存管理机制】

    六.内存管理机制 1.内存管理架构 2.小块空间的内存池 3.循环引用的垃圾收集 4.python中的垃圾收集 1.内存管理架构 Python内存管理机制有两套实现,由编译符号PYMALLOC_DEB ...

随机推荐

  1. 北京Uber优步司机奖励政策(10月19日~10月25日)

    用户组:优步北京人民优步A组(适用于10月19日-10月25日) 滴快车单单2.5倍,注册地址:http://www.udache.com/ 如何注册Uber司机(全国版最新最详细注册流程)/月入2万 ...

  2. 南京Uber优步司机奖励政策(7.20~7.26)

    人民优步奖励前提   *必须满足当周平均评分4.5星及以上,且当周接单率70%及以上,满足以上所有前提即可获得当周奖励 *刷单和红线行为立即封号并取消当周全部奖励及车费! 滴滴快车单单2.5倍,注册地 ...

  3. 4、Java并发编程:synchronized

    Java并发编程:synchronized 虽然多线程编程极大地提高了效率,但是也会带来一定的隐患.比如说两个线程同时往一个数据库表中插入不重复的数据,就可能会导致数据库中插入了相同的数据.今天我们就 ...

  4. springBoot 中webSocket 应用一

    <html> <head> <meta charset="UTF-8"> <title>websocket测试</title& ...

  5. beego orm mysql

    beego框架中的rom支持mysql 项目中使用到mvc模式,总结下使用方式: models中 package models import ( //使用beego orm 必备 "gith ...

  6. PS 放大眼睛

    1.打开图片,Ctrl+J 复制一个 2.选择工具栏的滤镜--液化 然后选择膨胀工具--设置画笔属性

  7. hdu1061Rightmost Digit(快速幂取余)

    Rightmost Digit Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)T ...

  8. OSG-视口&LOD&Imposter

    本文转至http://www.cnblogs.com/shapherd/archive/2010/08/10/osg.html 作者写的比较好,再次收藏,希望更多的人可以看到这个文章 互联网是是一个相 ...

  9. div布局方案整理

    实际项目开发过程中遇到页面 DIV 左右布局的需求:左侧 DIV 固定宽度,右侧 DIV 自适应宽度,填充满剩余页面,由此引申出本文的几种解决方案 1 左侧 DIV 设置 float 属性为 left ...

  10. Python|一文简单看懂 深度&广度 优先算法

    一.前言 以后尽量每天更新一篇,也是自己的一个学习打卡!加油!今天给大家分享的是,Python里深度/广度优先算法介绍及实现. 二.深度.广度优先算法简介 1. 深度优先搜索(DepthFirstSe ...