# float

# 内部结构

# PyFloatObject

typedef struct {
    PyObject_HEAD
    double ob_fval;
} PyFloatObject;

# PyFloat_Type

PyFloat_Type 中保存了很多关于浮点对象的 元信息 ,关键字段包括:

  • tp_name 字段保存类型名称,常量 float ;
  • tp_dealloc 、 tp_init 、 tp_alloc 和 tp_new 字段是对象创建销毁相关函数;
  • tp_repr 字段是生成语法字符串表示形式的函数;
  • tp_str 字段是生成普通字符串表示形式的函数;
  • tp_as_number 字段是数值操作集;
  • ​​tp_hash 字段是哈希值生成函数;
PyTypeObject PyFloat_Type = {
    PyVarObject_HEAD_INIT(&PyType_Type, 0)
    "float",
    sizeof(PyFloatObject),
    0,
    (destructor)float_dealloc,                  /* tp_dealloc */
    0,                                          /* tp_print */
    0,                                          /* tp_getattr */
    0,                                          /* tp_setattr */
    0,                                          /* tp_reserved */
    (reprfunc)float_repr,                       /* tp_repr */
    &float_as_number,                           /* tp_as_number */
    0,                                          /* tp_as_sequence */
    0,                                          /* tp_as_mapping */
    (hashfunc)float_hash,                       /* tp_hash */
    0,                                          /* tp_call */
    (reprfunc)float_repr,                       /* tp_str */
    PyObject_GenericGetAttr,                    /* tp_getattro */
    0,                                          /* tp_setattro */
    0,                                          /* tp_as_buffer */
    Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,   /* tp_flags */
    float_new__doc__,                           /* tp_doc */
    0,                                          /* tp_traverse */
    0,                                          /* tp_clear */
    float_richcompare,                          /* tp_richcompare */
    0,                                          /* tp_weaklistoffset */
    0,                                          /* tp_iter */
    0,                                          /* tp_iternext */
    float_methods,                              /* tp_methods */
    0,                                          /* tp_members */
    float_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 */
    float_new,                                  /* tp_new */
};

image

# 对象创建

# 对象创建API

  • 除了通用的创建对象的流程,Python为内置对象实现了对象创建API,简化了调用:

    • PyObject * PyFloat_FromDouble(double fval);​从浮点数创建浮点对象

      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;
      }
      
    • PyObject * PyFloat_FromString(PyObject *v);​从字符串创建浮点对象

# 对象销毁

  • 当对象不再需要时, Python 通过 Py_DECREF 或者 Py_XDECREF 宏减少引用计数

  • 当引用计数降为 0 时, Python 通过 _Py_Dealloc 宏回收对象

    • 实际调用的类型的tp_dealloc函数指针指向的函数

# 空闲对象缓存池

  • 例如浮点运算备受设计到大量临时对象的创建以及销毁,这则意味着大量内存分配回收操作

  • 因此Python在浮点对象销毁后,并不马上回收内存,而是将其加入一个空闲链表,后续需要创建浮点对象时,先到空闲链表中取,省去分配内存的开销。

    if (numfree >= PyFloat_MAXFREELIST)  {
        PyObject_FREE(op);
        return;
    }
    numfree++;
    Py_TYPE(op) = (struct _typeobject *)free_list;
    free_list = op;
    
  • 空闲链表定义在Objects/floatobject.c​中

    #ifndef PyFloat_MAXFREELIST
    #define PyFloat_MAXFREELIST    100	// 最大长度
    #endif
    static int numfree = 0;			// 当前长度
    static PyFloatObject *free_list = NULL; // 链表头部
    
    • 为了保持简洁,Python 把 ob_type 字段当作 next 指针来用,将空闲对象串成链表

      image

# 对象的行为

  • PyFloat_Type 中定义了很多函数指针,包括 tp_repr 、 tp_str 、 tp_hash 等,这些函数指针将一起决定 float 对象的行为。

    • 例如tp_hash 函数决定浮点哈希值的计算,tp_hash 函数指针指向 float_hash 函数,实现了针对浮点对象的哈希值算法:

      static Py_hash_t
      float_hash(PyFloatObject *v)
      {
          return _Py_HashDouble(v->ob_fval);
      }