2. Python3原始碼—浮點物件

阿里云云棲社群發表於2019-02-16

2.1. 浮點物件

浮點物件是“定長物件”。

2.1.1. Python中的建立

Python中浮點物件建立最重要的方法為PyFloat_FromDouble,如下Python語句最終會呼叫到PyFloat_FromDouble:

a = 1.23
b = float(1.234)

2.1.2. PyFloat_FromDouble的C呼叫棧

詞法解析,最終調到PyFloat_FromDouble,呼叫順序如下:

// ast.c
ast_for_expr
=>ast_for_power
=>ast_for_atom_expr
=>ast_for_atom (case NUMBER)
=>parsenumber
=>parsenumber_raw

// floatobject.c
=> PyFloat_FromDouble

2.1.3. PyFloat_FromDouble的C原始碼

// floatobject.c
PyObject *
PyFloat_FromDouble(double fval)
{
    PyFloatObject *op = free_list;
    if (op != NULL) {
        free_list = (PyFloatObject *) Py_TYPE(op);
        numfree--;
    } else {
        op = (PyFloatObject*) PyObject_MALLOC(sizeof(PyFloatObject));
        if (!op)
            return PyErr_NoMemory();
    }
    /* Inline PyObject_New */
    (void)PyObject_INIT(op, &PyFloat_Type);
    op->ob_fval = fval;
    return (PyObject *) op;
}

可以看到:

  • 浮點物件的C資料結構,所以Python中的浮點物件,實際上是C中的double。
// floatobject.h
typedef struct {
    PyObject_HEAD
    double ob_fval;
} PyFloatObject;
  • 採用浮點物件緩衝池
// floatobject.c
#ifndef PyFloat_MAXFREELIST
#define PyFloat_MAXFREELIST    100
#endif
static int numfree = 0;
static PyFloatObject *free_list = NULL;

static void
float_dealloc(PyFloatObject *op)
{
    if (PyFloat_CheckExact(op)) {
        if (numfree >= PyFloat_MAXFREELIST)  {
            PyObject_FREE(op);
            return;
        }
        numfree++;
        Py_TYPE(op) = (struct _typeobject *)free_list;
        free_list = op;
    }
    else
        Py_TYPE(op)->tp_free((PyObject *)op);
}

PyObject *
PyFloat_FromDouble(double fval)
{
    PyFloatObject *op = free_list;
    if (op != NULL) {
        free_list = (PyFloatObject *) Py_TYPE(op);
        numfree--;
    } else {
        op = (PyFloatObject*) PyObject_MALLOC(sizeof(PyFloatObject));
        if (!op)
            return PyErr_NoMemory();
    }
    /* Inline PyObject_New */
    (void)PyObject_INIT(op, &PyFloat_Type);
    op->ob_fval = fval;
    return (PyObject *) op;
}

float_dealloc和PyFloat_FromDouble方法針對free_list和numfree的操作構成了Python的浮點物件緩衝池技術。採用連結串列,值得注意的是Py_TYPE(op),在此處被當做next指標。緩衝池大小有上限,Python3中為100。

  • PyObject_INIT

    因為是定長物件,所以呼叫PyObject_INIT方法,與PyObject_INIT_VAR方法相比,只是少呼叫Py_SIZE(op) =(size)

2.2. 浮點物件的特性

2.2.1. 數值計算

// floatobject.c
&float_as_number,                           /* tp_as_number */

浮點物件的數值計算由float_as_number定義:

// floatobject.c
static PyNumberMethods float_as_number = {
    float_add,          /* nb_add */
    float_sub,          /* nb_subtract */
    float_mul,          /* nb_multiply */
    float_rem,          /* nb_remainder */
    float_divmod,       /* nb_divmod */
    float_pow,          /* nb_power */
    (unaryfunc)float_neg, /* nb_negative */
    float_float,        /* nb_positive */
    (unaryfunc)float_abs, /* nb_absolute */
    (inquiry)float_bool, /* nb_bool */
    0,                  /* nb_invert */
    0,                  /* nb_lshift */
    0,                  /* nb_rshift */
    0,                  /* nb_and */
    0,                  /* nb_xor */
    0,                  /* nb_or */
    float___trunc___impl, /* nb_int */
    0,                  /* nb_reserved */
    float_float,        /* nb_float */
    0,                  /* nb_inplace_add */
    0,                  /* nb_inplace_subtract */
    0,                  /* nb_inplace_multiply */
    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 */
    float_floor_div,    /* nb_floor_divide */
    float_div,          /* nb_true_divide */
    0,                  /* nb_inplace_floor_divide */
    0,                  /* nb_inplace_true_divide */
};

2.2.2. to string

// floatobject.c
(reprfunc)float_repr,                       /* tp_repr */
(reprfunc)float_repr,                       /* tp_str */

2.2.3. hash

// floatobject.c
(hashfunc)float_hash,                       /* tp_hash */

2.2.4. 比較

// floatobject.c
float_richcompare,                        /* tp_richcompare */

2.2.5. 內建方法

// floatobject.c
float_methods,                              /* tp_methods */

2.2.6. 內建屬性

// floatobject.c
float_getset,                                /* tp_getset */

2.3 參考

  • Python原始碼剖析

本文作者:whj0709
閱讀原文
本文為雲棲社群原創內容,未經允許不得轉載。

相關文章