{人面不知何去处 桃花依旧笑春风}

py3源码[3]-其它数值类型

Posted in Uncategorized by interma on 2012/10/23

除了PyIntObject(2.x)和PyLongObject之外,还有如下几种数值类型:

一,bool

//boolobject.c
//True和False都是对PyLongObject的一个封装
struct _longobject _Py_FalseStruct = {
    PyVarObject_HEAD_INIT(&PyBool_Type, 0) //ob_size=0
    { 0 } //ob_digit=0
};
struct _longobject _Py_TrueStruct = {
    PyVarObject_HEAD_INIT(&PyBool_Type, 1) //ob_size=1
    { 1 }
};

tips:
1,bool的tp_base是PyLong_Type,所以可以:
>>> a=[1,2,3]
>>> a[True]
2
>>> 1==True
True
>>> 0==False
True
2,判断object是否为True,”所有零值或内容长度为零的对象都被视为False”。

//object.c
int
PyObject_IsTrue(PyObject *v)
{
    Py_ssize_t res;
    if (v == Py_True)
        return 1;
    if (v == Py_False)
        return 0;
    if (v == Py_None)
        return 0;
    else if (v->ob_type->tp_as_number != NULL &&
             v->ob_type->tp_as_number->nb_bool != NULL)
        res = (*v->ob_type->tp_as_number->nb_bool)(v);
    else if (v->ob_type->tp_as_mapping != NULL &&
             v->ob_type->tp_as_mapping->mp_length != NULL)
        res = (*v->ob_type->tp_as_mapping->mp_length)(v);
    else if (v->ob_type->tp_as_sequence != NULL &&
             v->ob_type->tp_as_sequence->sq_length != NULL)
        res = (*v->ob_type->tp_as_sequence->sq_length)(v);
    else
        return 1;
    /* if it is negative, it should be either -1 or -2 */
    return (res > 0) ? 1 : Py_SAFE_DOWNCAST(res, Py_ssize_t, int);
}

二,float

//floatobject.h
typedef struct {
    PyObject_HEAD //定长对象
    double ob_fval; //内部使用c double类型包装
} PyFloatObject;

tips:
1,也使用了free_list,不过区别于2.x中的PyIntObject,free_list有最长长度限制

#ifndef PyFloat_MAXFREELIST
#define PyFloat_MAXFREELIST    100 
#endif
static int numfree = 0;
static PyFloatObject *free_list = NULL;

PyObject * PyFloat_FromDouble(double fval)
{
    register PyFloatObject *op = free_list;
    if (op != NULL) { //free_list中有空间,直接用
        free_list = (PyFloatObject *) Py_TYPE(op);
        numfree--;
    } else { //否则,malloc出来即可
        op = (PyFloatObject*) PyObject_MALLOC(sizeof(PyFloatObject));
        if (!op)
            return PyErr_NoMemory();
    }
    /* Inline PyObject_New */
    PyObject_INIT(op, &PyFloat_Type);
    op->ob_fval = fval;
    return (PyObject *) op;
}

static void float_dealloc(PyFloatObject *op)
{
    if (PyFloat_CheckExact(op)) {
        if (numfree >= PyFloat_MAXFREELIST)  { // 超出最大长度就直接free掉
            PyObject_FREE(op);
            return;
        }
        numfree++;
        Py_TYPE(op) = (struct _typeobject *)free_list;
        free_list = op;
    }
    else
        Py_TYPE(op)->tp_free((PyObject *)op);
}

三,复数

//complexobjec.h
typedef struct {
    double real;
    double imag;
} Py_complex;

>>> a=complex(1.2,1.5)
>>> a
(1.2+1.5j)

四,分数
lib实现:import fractions。
不赘述,请参考:http://woodpecker.org.cn/diveintopython3/native-datatypes.html

参考:
1,雨痕-深入Python编程-RC0.3.pdf
2,http://woodpecker.org.cn/diveintopython3/

Tagged with:

py3源码[2]-整数

Posted in Uncategorized by interma on 2012/10/11

根据PEP 0237,Py3中已经没有int类型了,py3中的整数对象指的只有PyLongObject了(关于Py2.x中的PyIntObject,《Python源码剖析》介绍的很详细了)。

整数的相关操作都在long_as_number操作集中。

先回答上篇文章遗留的2个问题:
1,PyLongObject的digit ob_digit[1]的作用?
A:是一个常量数组头(PyLongObject是不可变对象,不用考虑多态增长),对象初始化时分配所需要的实际空间并确定数据长度保存在PyObject_VAR_HEAD的ob_size中(tips:每个ob_digit只用了15位表示数字,ob_size的正负表示PyLongObject的正负)。
分析详解

2,long类型如何实现任意大整数的运算?
“PyLongObject是不可变对象,不用考虑多态增长,对象初始化时分配所需要的实际空间并确定数据长度保存在PyObject_VAR_HEAD的ob_size中”。示例:
加法的很简单

//longobject.c
/* Add the absolute values of two long integers. */
//低位开始诸位相加
static PyLongObject *
x_add(PyLongObject *a, PyLongObject *b)
{
    Py_ssize_t size_a = ABS(Py_SIZE(a)), size_b = ABS(Py_SIZE(b));
    PyLongObject *z;
    Py_ssize_t i;
    digit carry = 0;

    /* Ensure a is the larger of the two: */
    if (size_a < size_b) {
        { PyLongObject *temp = a; a = b; b = temp; }
        { Py_ssize_t size_temp = size_a;
            size_a = size_b;
            size_b = size_temp; }
    }
    z = _PyLong_New(size_a+1);
    if (z == NULL)
        return NULL;
    for (i = 0; i < size_b; ++i) {
        carry += a->ob_digit[i] + b->ob_digit[i];
        z->ob_digit[i] = carry & PyLong_MASK;
        carry >>= PyLong_SHIFT;
    }
    for (; i < size_a; ++i) {
        carry += a->ob_digit[i];
        z->ob_digit[i] = carry & PyLong_MASK;
        carry >>= PyLong_SHIFT;
    }
    z->ob_digit[i] = carry;
    return long_normalize(z);
}

乘法则复杂很多,Karatsuba算法(O(n^2)=>O(n^1.58))。
分析详解

依然使用了类似PyIntObject实现中的小整数对象池

//longobject.c
#ifndef NSMALLPOSINTS
#define NSMALLPOSINTS           257
#endif
#ifndef NSMALLNEGINTS
#define NSMALLNEGINTS           5
#endif
/* Small integers are preallocated in this array so that they
   can be shared.
   The integers that are preallocated are those in the range
   -NSMALLNEGINTS (inclusive) to NSMALLPOSINTS (not inclusive).
*/
static PyLongObject small_ints[NSMALLNEGINTS + NSMALLPOSINTS];

tips:
1,int _PyLong_Init(void)
初始化了这个小整数对象池
2,PyObject * PyLong_FromLong(long ival)
展示了如何从c的long类型建立一个PyLong(小整数使用池,其他整数直接malloc)。

问题:
1,《Python源码剖析》提到的整数对象池block_list应该已经不存在了(因为PyLongObject为变长对象)。
既然没有池了,malloc/free会带来的不小性能损耗,这也许是py3性能损耗的一个方面:”Py3.0运行 pystone benchmark的速度比Py2.5慢30%。Guido认为Py3.0有极大的优化空间,在字符串和整形操作上可以取得很好的优化结果。”
另外:底层还有arena这层内存管理机制。

2,long_normalize是否会导致内存泄漏?

/* Normalize (remove leading zeros from) a long int object.
   Doesn't attempt to free the storage--in most cases, due to the nature
   of the algorithms used, this could save at most be one word anyway. */
static PyLongObject * long_normalize(register PyLongObject *v)

参考:
1,python内部细节实现好文:www.endless-loops.com/tag/python

Tagged with:

py3源码[0]-前言声明

Posted in Uncategorized by interma on 2012/10/08

ver Python-3.3.0
http://www.python.org/download/releases/3.3.0/

基本是结合《Python源码剖析》(http://book.douban.com/subject/3117898/)来写的,加上了自己发散扩展的一些内容。

人生很长,专心做一点喜欢的事情吧。

Tagged with:

py3源码[1]-object基础

Posted in Uncategorized by interma on 2012/10/08

几个重要的struct

//1,基础对象(头)
typedef struct _object {
    _PyObject_HEAD_EXTRA //only for trace
    Py_ssize_t ob_refcnt; //引用计数
    struct _typeobject *ob_type; //指向类型对象(PyTypeObject),它们都是全局变量,例子see 5
} PyObject;

//2,变长对象(头)
typedef struct {
    PyObject ob_base;
    Py_ssize_t ob_size; //抽象元素数目,非字节
} PyVarObject;

//3,类型举例:long
typedef struct _longobject PyLongObject;
struct _longobject {
    PyObject_VAR_HEAD //PyVarObject
    digit ob_digit[1]; //?
};

//4,类型举例:dict
typedef struct {
    PyObject_HEAD //PyObject
    Py_ssize_t ma_used;
    PyDictKeysObject *ma_keys;
    PyObject **ma_values;
} PyDictObject;

//5,long类型对象(PyTypeObject)
//longobject.c
//各个内部类型实际上都是对象,类型对象的类型则是PyType_Type
PyTypeObject PyLong_Type = {
    PyVarObject_HEAD_INIT(&amp;PyType_Type, 0)  //对应到PyVarObject头的3个字段
    "int",                                      /* tp_name */
    offsetof(PyLongObject, ob_digit),           /* tp_basicsize */
    sizeof(digit),                              /* tp_itemsize */
    long_dealloc,                               /* tp_dealloc */
    0,                                          /* tp_print */
    0,                                          /* tp_getattr */
    0,                                          /* tp_setattr */
    0,                                          /* tp_reserved */
    long_to_decimal_string,                     /* tp_repr */
    &amp;long_as_number,                            /* tp_as_number */ //数值操作函数集
    0,                                          /* tp_as_sequence */
    0,                                          /* tp_as_mapping */
    (hashfunc)long_hash,                        /* tp_hash */
    0,                                          /* tp_call */
    long_to_decimal_string,                     /* tp_str */
    PyObject_GenericGetAttr,                    /* tp_getattro */
    0,                                          /* tp_setattro */
    0,                                          /* tp_as_buffer */
    Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE |
        Py_TPFLAGS_LONG_SUBCLASS,               /* tp_flags */
    long_doc,                                   /* tp_doc */
    0,                                          /* tp_traverse */
    0,                                          /* tp_clear */
    long_richcompare,                           /* tp_richcompare */
    0,                                          /* tp_weaklistoffset */
    0,                                          /* tp_iter */
    0,                                          /* tp_iternext */
    long_methods,                               /* tp_methods */
    0,                                          /* tp_members */
    long_getset,                                /* 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 */
    long_new,                                   /* tp_new */
    PyObject_Del,                               /* tp_free */
};

tips:
1,py2 long/int => py3 int
PEP 0237: Essentially, long renamed to int. That is, there is only one built-in integral type, named int; but it behaves mostly like the old long type.
2,关于Py_LIMITED_API
避免extension使用不稳定的py api。
http://docs.python.org/release/3.2.3/whatsnew/3.2.html#pep-384-defining-a-stable-abi
3,PyObject*
泛型指针,可以指向任何一个Py对象,通过ob_type字段实现了多态。

问题:
1,PyLong_Type的tp_base为0,没有继承PyObject?
A:yes,不过是可以通过PyObject*引用的。
2,PyLongObject的digit ob_digit[1]的作用?
3,long类型如何实现任意大整数的运算?
A:这2个问题答案在下一篇文章中给出吧。

Tagged with: