CPython源码学习3:浮点数对象

2024-06-03 01:12

本文主要是介绍CPython源码学习3:浮点数对象,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

浮点数的结构体 PyFloatObject

浮点数的结构体PyFloatObject ,定义在头文件 Include/floatobject.h 中,可以看出浮点数底层使用 C 的double类型来存储真正的值。

// Include/floatobject.h
typedef struct {PyObject_HEADdouble ob_fval;		// 底层使用C的double类型,存储真正的浮点数
} PyFloatObject;// 展开 PyObject_HEAD
typedef struct {_PyObject_HEAD_EXTRAPy_ssize_t ob_refcnt; // 引用计数 8字节struct _typeobject *ob_type; // 类型 8字节double ob_fval;  // 
}

浮点数内存大小

把PyFloatObject 展开后发现ob_refcnt 是整数型长度 8 字节,ob_type 是指针 长度 8 字节,ob_fval 是 double 型长度 8 字节,所以浮点数的大小是固定的 24 字节,可以在 Python 中验证。

a = 3.14
a.__sizeof__() # 24import math
math.pi # 3.141592653589793
math.pi.__sizeof__() # 24

浮点数类型对象 PyFloat_Type

浮点数类型的结构体是 PyFloat_Type,定义在头文件 Include/floatobject.c 中。提供了多个函数来检查和操作浮点数对象,包括浮点数的创建float_new、浮点数的销毁float_dealloc、浮点数的函数集float_as_number 包含加减乘除取余等计算、浮点数的哈希计算float_hash、用于生成浮点数字符串表示的函数float_repr 等等。

// Objects/floatobject.c
PyTypeObject PyFloat_Type = {PyVarObject_HEAD_INIT(&PyType_Type, 0)"float",					// 名称sizeof(PyFloatObject),						/*浮点型占用内存*/0,(destructor)float_dealloc,                  /* 对象的销毁 tp_dealloc 最终调用的是 float_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 */
};

值为 0 的字段表示这些字段在初始化时没有被显式赋值或使用了默认值,即最终调用的时候使用的是PyTypeObject 中对应的值。

  • tp_itemsize: 设为 0 表示这个类型对象没有额外的项目空间(通常用于变长对象,如列表)。
  • tp_print: 设为 0 表示没有定义打印函数。
  • tp_getattrtp_setattr: 设为 0 表示没有定义获取和设置属性的函数。
  • tp_compare: 设为 0 表示没有定义比较函数。
  • tp_call: 设为 0 表示这个类型对象不能被调用(即 float 对象不是可调用的)。

浮点数创建

创建对象都是调用tp_new 函数,浮点数对应的是float_new,可以看到最终调用了float_new_impl 函数,如果是字符串则调用 PyFloat_FromString 进行创建,否则调用PyNumber_Float,最终还是落在了PyFloat_FromDouble 或者PyFloat_FromString 函数上。

// Objects/clinic/floatobject.c.h
static PyObject *
float_new(PyTypeObject *type, PyObject *args, PyObject *kwargs)
{PyObject *return_value = NULL; // 定义最终的返回值PyObject *x = _PyLong_Zero;if ((type == &PyFloat_Type) &&!_PyArg_NoKeywords("float", kwargs)) {goto exit;}if (!PyArg_UnpackTuple(args, "float",0, 1,&x)) {goto exit;}return_value = float_new_impl(type, x);exit:return return_value;
}// Objects/floatobject.c
static PyObject *
float_new_impl(PyTypeObject *type, PyObject *x)
/*[clinic end generated code: output=ccf1e8dc460ba6ba input=540ee77c204ff87a]*/
{if (type != &PyFloat_Type)return float_subtype_new(type, x); /* Wimp out *//* 如果是字符串类型的浮点数 */if (PyUnicode_CheckExact(x))return PyFloat_FromString(x);return PyNumber_Float(x);
}// Objects/abstract.c
PyObject *
PyNumber_Float(PyObject *o)
{PyNumberMethods *m;if (o == NULL) {return null_error();}if (PyFloat_CheckExact(o)) {// 如果是hi浮点数类型,引用计数增加后返回Py_INCREF(o);return o;}m = o->ob_type->tp_as_number;if (m && m->nb_float) { /* 如果是浮点数的子类型,并且实现了nb_float方法 */PyObject *res = m->nb_float(o);double val;if (!res || PyFloat_CheckExact(res)) {return res;}if (!PyFloat_Check(res)) {PyErr_Format(PyExc_TypeError,"%.50s.__float__ returned non-float (type %.50s)",o->ob_type->tp_name, res->ob_type->tp_name);Py_DECREF(res);return NULL;}/* Issue #26983: warn if 'res' not of exact type float. */if (PyErr_WarnFormat(PyExc_DeprecationWarning, 1,"%.50s.__float__ returned non-float (type %.50s).  ""The ability to return an instance of a strict subclass of float ""is deprecated, and may be removed in a future version of Python.",o->ob_type->tp_name, res->ob_type->tp_name)) {Py_DECREF(res);return NULL;}val = PyFloat_AS_DOUBLE(res);Py_DECREF(res);return PyFloat_FromDouble(val);}if (PyFloat_Check(o)) { /*浮点数的子类型,没实现nb_float方法*,转换成double型再进行初始化 */return PyFloat_FromDouble(PyFloat_AS_DOUBLE(o));}return PyFloat_FromString(o);
}

从创建过程中可以看到,CPython 最终归结到两个创建浮点数的函数,这两个都是 C API 并且是特殊的只针对于创建浮点对象的:

PyFloat_FromDouble

PyAPI_FUNC(PyObject *) PyFloat_FromDouble(double);通过 C 的 double 来创建浮点对象

// Objects/floatobject.c
PyObject *
PyFloat_FromDouble(double fval)
{// op指向free_list中的第一个PyFloatObject对象PyFloatObject *op = free_list;if (op != NULL) {// // 将op对象的ob_type,转为PyFloatObject,当作链表的next指针// op是PyFloatObject,而它的ob_type本应该是PyFloat_Type// 将 free_list 指向 op 的 ob_type 所指的对象,并将其转换为PyFloatObject对象free_list = (PyFloatObject *) Py_TYPE(op);numfree--;} else {// 新建浮点对象,并且动态申请内存,大小为结构体PyFloatObjectop = (PyFloatObject*) PyObject_MALLOC(sizeof(PyFloatObject));if (!op)return PyErr_NoMemory();}/* Inline PyObject_New */// 初始化 ob_refcnt为1,ob_type为PyFloat_Type(void)PyObject_INIT(op, &PyFloat_Type);// 初始化ob_fval为传进来的参数fvalop->ob_fval = fval;// 最终返回的泛类型对象return (PyObject *) op;
}// Include/objimpl.h
// op 实例对象的指针,typeobj 类型对象的指针
// Py_TYPE(op) = (typeobj) 将op所指对象的类型设置为传参进来的 typeobj
// _Py_NewReference((PyObject *)(op)) 将op所指对象的引用计数器设置为1
#define PyObject_INIT(op, typeobj) \( Py_TYPE(op) = (typeobj), _Py_NewReference((PyObject *)(op)), (op) )

PyFloat_FromDouble 的创建过程是:
1、创建浮点对象,并分配内存,如果缓存池中有对象的话可以拿过来直接使用,这样为了提高效率,节省内存。
2、使用宏定义 PyObject_INIT 初始化引用计数器和指针类型。
3、给浮点对象的 ob_fval 赋值,最终的值是存在 ob_fval 中的。
4、最终返回泛类型PyObject * 。

PyFloat_FromString

PyAPI_FUNC(PyObject *) PyFloat_FromString(PyObject*);通过 python 的字符串创建浮点对象

// Objects/floatobject.c
PyObject *
PyFloat_FromString(PyObject *v)
{const char *s; // 指向输入字符串v的指针PyObject *s_buffer = NULL; // 临时对象,用于存储转换后的字符串Py_ssize_t len; // 输入字符串的长度 Py_buffer view = {NULL, NULL}; // 是一个 Py_buffer 结构体,用于处理字节串的情况PyObject *result = NULL; // 最终返回的 Python 浮点数对象if (PyUnicode_Check(v)) {// 将 Unicode 字符串中的十进制数字字符和空格字符转换为其对应的 ASCII 字符s_buffer = _PyUnicode_TransformDecimalAndSpaceToASCII(v);if (s_buffer == NULL)return NULL;assert(PyUnicode_IS_ASCII(s_buffer));/* Simply get a pointer to existing ASCII characters. */// 转换为 UTF-8 编码的 C 字符串s = PyUnicode_AsUTF8AndSize(s_buffer, &len);assert(s != NULL);}else if (PyBytes_Check(v)) {// 处理字节的情况,直接获取其内部的 C 字符串和长度s = PyBytes_AS_STRING(v);len = PyBytes_GET_SIZE(v);}else if (PyByteArray_Check(v)) {// 处理字节数组的情况,直接获取其内部的 C 字符串和长度s = PyByteArray_AS_STRING(v);len = PyByteArray_GET_SIZE(v);}else if (PyObject_GetBuffer(v, &view, PyBUF_SIMPLE) == 0) {// 处理缓冲区字节s = (const char *)view.buf;len = view.len;/* Copy to NUL-terminated buffer. */s_buffer = PyBytes_FromStringAndSize(s, len);if (s_buffer == NULL) {PyBuffer_Release(&view);return NULL;}s = PyBytes_AS_STRING(s_buffer);}else {// 输入对象是其他类型,则抛出 TypeError 异常PyErr_Format(PyExc_TypeError,"float() argument must be a string or a number, not '%.200s'",Py_TYPE(v)->tp_name);return NULL;}// 将字符串转换为浮点数result = _Py_string_to_number_with_underscores(s, len, "float", v, v,float_from_string_inner);// 释放缓冲区并清理临时对象PyBuffer_Release(&view);// 缓冲区中对象的引用计数器减1Py_XDECREF(s_buffer);return result;
}// 将字符串转换为浮点对象
static PyObject *
float_from_string_inner(const char *s, Py_ssize_t len, void *obj)
{double x;const char *end;const char *last = s + len;/* strip space 在字符串末尾跳过空白字符,确保整个字符串都被正确解析。 */while (s < last && Py_ISSPACE(*s)) {s++;}while (s < last - 1 && Py_ISSPACE(last[-1])) {last--;}/* We don't care about overflow or underflow.  If the platform* supports them, infinities and signed zeroes (on underflow) are* fine. 将字符串转换为 double 类型。*/x = PyOS_string_to_double(s, (char **)&end, NULL);if (end != last) {PyErr_Format(PyExc_ValueError,"could not convert string to float: ""%R", obj);return NULL;}else if (x == -1.0 && PyErr_Occurred()) {return NULL;}else {return PyFloat_FromDouble(x);}
}

PyFloat_FromDouble 的创建过程是:

  1. 字符串检查和转换
  • 检查输入对象是否为 Unicode 字符串或字节串。
  • 如果是 Unicode 字符串,则将其转换为 UTF-8 编码的 C 字符串。
  • 如果是字节串,则直接获取其内部的 C 字符串。
  • 如果是其他类型抛出异常。
  1. 字符串转换为浮点数
  • 调用_Py_string_to_number_with_underscores 和 float_from_string_inner 函数,将字符串转换为 double 类型。
  • 可以看到 float_from_string_inner 中调用 PyOS_string_to_double,将字符串转换为 double 型,函数最终落在了 PyFloat_FromDouble 上。
  1. 清理缓冲区
  • 浮点对象创建完成后,释放缓冲区,清理缓冲区的引用计数。

浮点数销毁

销毁对象是调用指针 tp_dealloc 所指的函数,浮点数对象对应的就是 float_dealloc

// Objects/floatobject.cstatic void
float_dealloc(PyFloatObject *op)
{if (PyFloat_CheckExact(op)) {// 缓存池满了,不能放了,就直接销毁对象if (numfree >= PyFloat_MAXFREELIST)  {PyObject_FREE(op);return;}// 缓存池没满,就放到缓存池中numfree++;// free_list 是 PyFloatObject 类型的 将 free_list 转换为_typeobject// 然后让 op的ob_type指向free_listPy_TYPE(op) = (struct _typeobject *)free_list;// 链表操作,让free_list指向链表的头部 op是 PyFloatObject类型的free_list = op;}else// 不是PyFloat_Type类型,通过该对象的tp_free直接释放Py_TYPE(op)->tp_free((PyObject *)op);
}

浮点数的缓存机制

浮点数的缓存机制是以链表形式存在的,free_list 是PyFloatObject 类型的,所有回收的浮点对象都链在了free_list 上,numfree 则记录了链表中可用的对象个数,PyFloat_MAXFREELIST 表示缓存的容量。

// Objects/floatobject.c
#ifndef PyFloat_MAXFREELIST
#define PyFloat_MAXFREELIST    100  // 限制 free_list 最大数量
#endif
static int numfree = 0;             // 记录free_list中可用对象的个数
// 定义链表,类型为PyFloatObject,ob_type指向的应该是PyFloat_Type,
// 在链表中对象的ob_type指向的是下一个PyFloatObject
static PyFloatObject *free_list = NULL; // PyFloat_FromDouble 函数中 获取缓存
// op指向free_list中的第一个PyFloatObject对象
PyFloatObject *op = free_list;
if (op != NULL) {// // 将op对象的ob_type,转为PyFloatObject,当作链表的next指针// op是PyFloatObject,而它的ob_type本应该是PyFloat_Type// 将 free_list 指向 op 的 ob_type 所指的对象,并将其转换为PyFloatObject对象free_list = (PyFloatObject *) Py_TYPE(op);numfree--;
}// float_dealloc 函数中,放入缓存
// 缓存池满了,不能放了,就直接销毁对象
if (numfree >= PyFloat_MAXFREELIST)  {PyObject_FREE(op);return;
}
// 缓存池没满,就放到缓存池中
numfree++;
// free_list 是 PyFloatObject 类型的 将 free_list 转换为_typeobject
// 然后让 op的ob_type指向free_list
Py_TYPE(op) = (struct _typeobject *)free_list;
// 链表操作,让free_list指向链表的头部 op是 PyFloatObject类型的
free_list = op;

缓存的工作方式

1、 当需要创建一个新的浮点数对象时,解释器会首先检查free_list 链表中是否有可用的对象。
2、 如果有,则直接返回缓存链表中的第一个,如果没有,则重新创建一个新的浮点数对象。
3、当一个浮点数对象不再被引用时(例如引用计数归零),它可能会被销毁并释放内存。
4、释放时,如果缓存池的长度超过了PyFloat_MAXFREELIST 则直接销毁,否则将对象链到free_list 上。
备注:
1、将对象放入缓存池中时,会将要销毁的 op 对象放到 free_list 头部,使用 op 的 ob_type 当作 next 指针指向 free_list,ob_type 是 _typeobject(PyFloat_Type)类型,但是 free_list 是PyFloatObject 类型,所以为了节省性能会将free_list 转换成_typeobject。
2、从缓存池中获取对象时,也是获取free_list 头部对象,先将 op 指向free_list,再将free_list 指向 op 的ob_type 所指的对象,并且将其转换为PyFloatObject 类型。

浮点数的属性和函数

PyFloat_Type 中还定义了一些浮点数相关的属性和函数等
float_hash 浮点数的哈希值

/*
a = 3.14
hash(a)   # 322818021289917443
*/
// Objects/floatobject.c
static Py_hash_t
float_hash(PyFloatObject *v)
{// 计算ob_fval的哈希值return _Py_HashDouble(v->ob_fval);
}

float_richcompare 浮点数的比较

// Objects/floatobject.c
static PyObject*
float_richcompare(PyObject *v, PyObject *w, int op)
{double i, j;int r = 0;assert(PyFloat_Check(v));i = PyFloat_AS_DOUBLE(v);/* Switch on the type of w.  Set i and j to doubles to be compared,* and op to the richcomp to use.*/if (PyFloat_Check(w))j = PyFloat_AS_DOUBLE(w);else if (!Py_IS_FINITE(i)) {if (PyLong_Check(w))/* If i is an infinity, its magnitude exceeds any* finite integer, so it doesn't matter which int we* compare i with.  If i is a NaN, similarly.*/j = 0.0;elsegoto Unimplemented;}else if (PyLong_Check(w)) {int vsign = i == 0.0 ? 0 : i < 0.0 ? -1 : 1;int wsign = _PyLong_Sign(w);size_t nbits;int exponent;if (vsign != wsign) {/* Magnitudes are irrelevant -- the signs alone* determine the outcome.*/i = (double)vsign;j = (double)wsign;goto Compare;}/* The signs are the same. *//* Convert w to a double if it fits.  In particular, 0 fits. */nbits = _PyLong_NumBits(w);if (nbits == (size_t)-1 && PyErr_Occurred()) {/* This long is so large that size_t isn't big enough* to hold the # of bits.  Replace with little doubles* that give the same outcome -- w is so large that* its magnitude must exceed the magnitude of any* finite float.*/PyErr_Clear();i = (double)vsign;assert(wsign != 0);j = wsign * 2.0;goto Compare;}if (nbits <= 48) {j = PyLong_AsDouble(w);/* It's impossible that <= 48 bits overflowed. */assert(j != -1.0 || ! PyErr_Occurred());goto Compare;}assert(wsign != 0); /* else nbits was 0 */assert(vsign != 0); /* if vsign were 0, then since wsign is* not 0, we would have taken the* vsign != wsign branch at the start *//* We want to work with non-negative numbers. */if (vsign < 0) {/* "Multiply both sides" by -1; this also swaps the* comparator.*/i = -i;op = _Py_SwappedOp[op];}assert(i > 0.0);(void) frexp(i, &exponent);/* exponent is the # of bits in v before the radix point;* we know that nbits (the # of bits in w) > 48 at this point*/if (exponent < 0 || (size_t)exponent < nbits) {i = 1.0;j = 2.0;goto Compare;}if ((size_t)exponent > nbits) {i = 2.0;j = 1.0;goto Compare;}/* v and w have the same number of bits before the radix* point.  Construct two ints that have the same comparison* outcome.*/{double fracpart;double intpart;PyObject *result = NULL;PyObject *vv = NULL;PyObject *ww = w;if (wsign < 0) {ww = PyNumber_Negative(w);if (ww == NULL)goto Error;}elsePy_INCREF(ww);fracpart = modf(i, &intpart);vv = PyLong_FromDouble(intpart);if (vv == NULL)goto Error;if (fracpart != 0.0) {/* Shift left, and or a 1 bit into vv* to represent the lost fraction.*/PyObject *temp;temp = PyNumber_Lshift(ww, _PyLong_One);if (temp == NULL)goto Error;Py_DECREF(ww);ww = temp;temp = PyNumber_Lshift(vv, _PyLong_One);if (temp == NULL)goto Error;Py_DECREF(vv);vv = temp;temp = PyNumber_Or(vv, _PyLong_One);if (temp == NULL)goto Error;Py_DECREF(vv);vv = temp;}r = PyObject_RichCompareBool(vv, ww, op);if (r < 0)goto Error;result = PyBool_FromLong(r);Error:Py_XDECREF(vv);Py_XDECREF(ww);return result;}} /* else if (PyLong_Check(w)) */else        /* w isn't float or int */goto Unimplemented;Compare:PyFPE_START_PROTECT("richcompare", return NULL)switch (op) {case Py_EQ:r = i == j;break;case Py_NE:r = i != j;break;case Py_LE:r = i <= j;break;case Py_GE:r = i >= j;break;case Py_LT:r = i < j;break;case Py_GT:r = i > j;break;}PyFPE_END_PROTECT(r)return PyBool_FromLong(r);Unimplemented:Py_RETURN_NOTIMPLEMENTED;
}

float_as_number 结构体是所有浮点数函数集,包含加、减、乘、除、取余、幂等

// Objects/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 */
};

介绍下加法运算 float_add,其他函数都是类似的可以在Objects/floatobject.c 中查看。

// Objects/floatobject.c
static PyObject *
float_add(PyObject *v, PyObject *w)
{// 先将python对象转换成C的doubledouble a,b;// 结构体无法运算,所以通过PyFloat_AS_DOUBLE 将PyFloatObject中的ob_fval值抽取出来// v的值赋给a,w的值赋给bCONVERT_TO_DOUBLE(v, a);CONVERT_TO_DOUBLE(w, b);// 保护浮点数计算,以确保即使发生异常,程序也不会崩溃PyFPE_START_PROTECT("add", return 0)a = a + b;PyFPE_END_PROTECT(a)// 计算完后转换成PyFloatObject对象return PyFloat_FromDouble(a);
}

浮点数相关的宏定义和函数

// 判断是否是PyFloatObject 或者 PyFloatObject 的子类型
#define PyFloat_Check(op) PyObject_TypeCheck(op, &PyFloat_Type)// 判断是否是 PyFloatObject 类型
#define PyFloat_CheckExact(op) (Py_TYPE(op) == &PyFloat_Type)// 返回一个 op 内容的 C double 即ob_fval的值,但没有错误检查
#define PyFloat_AS_DOUBLE(op) (((PyFloatObject *)(op))->ob_fval)/*
返回一个 C double 代表 op 的内容。 如果 op 不是一个 Python 浮点数对象但是具有 __float__() 方法,
此方法将首先被调用,将 op 转换成一个数点数。 如果 __float__() 未定义则将回退至 __index__()。
如果失败,此方法将返回 -1.0,因此开发者应当调用 PyErr_Occurred() 来检查错误
*/
double
PyFloat_AsDouble(PyObject *op)
{PyNumberMethods *nb;PyObject *res;double val;if (op == NULL) {PyErr_BadArgument();return -1;}if (PyFloat_Check(op)) {return PyFloat_AS_DOUBLE(op);}nb = Py_TYPE(op)->tp_as_number;if (nb == NULL || nb->nb_float == NULL) {PyErr_Format(PyExc_TypeError, "must be real number, not %.50s",op->ob_type->tp_name);return -1;}res = (*nb->nb_float) (op);if (res == NULL) {return -1;}if (!PyFloat_CheckExact(res)) {if (!PyFloat_Check(res)) {PyErr_Format(PyExc_TypeError,"%.50s.__float__ returned non-float (type %.50s)",op->ob_type->tp_name, res->ob_type->tp_name);Py_DECREF(res);return -1;}if (PyErr_WarnFormat(PyExc_DeprecationWarning, 1,"%.50s.__float__ returned non-float (type %.50s).  ""The ability to return an instance of a strict subclass of float ""is deprecated, and may be removed in a future version of Python.",op->ob_type->tp_name, res->ob_type->tp_name)) {Py_DECREF(res);return -1;}}val = PyFloat_AS_DOUBLE(res);Py_DECREF(res);return val;
}

这篇关于CPython源码学习3:浮点数对象的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1025615

相关文章

HarmonyOS学习(七)——UI(五)常用布局总结

自适应布局 1.1、线性布局(LinearLayout) 通过线性容器Row和Column实现线性布局。Column容器内的子组件按照垂直方向排列,Row组件中的子组件按照水平方向排列。 属性说明space通过space参数设置主轴上子组件的间距,达到各子组件在排列上的等间距效果alignItems设置子组件在交叉轴上的对齐方式,且在各类尺寸屏幕上表现一致,其中交叉轴为垂直时,取值为Vert

Ilya-AI分享的他在OpenAI学习到的15个提示工程技巧

Ilya(不是本人,claude AI)在社交媒体上分享了他在OpenAI学习到的15个Prompt撰写技巧。 以下是详细的内容: 提示精确化:在编写提示时,力求表达清晰准确。清楚地阐述任务需求和概念定义至关重要。例:不用"分析文本",而用"判断这段话的情感倾向:积极、消极还是中性"。 快速迭代:善于快速连续调整提示。熟练的提示工程师能够灵活地进行多轮优化。例:从"总结文章"到"用

【前端学习】AntV G6-08 深入图形与图形分组、自定义节点、节点动画(下)

【课程链接】 AntV G6:深入图形与图形分组、自定义节点、节点动画(下)_哔哩哔哩_bilibili 本章十吾老师讲解了一个复杂的自定义节点中,应该怎样去计算和绘制图形,如何给一个图形制作不间断的动画,以及在鼠标事件之后产生动画。(有点难,需要好好理解) <!DOCTYPE html><html><head><meta charset="UTF-8"><title>06

学习hash总结

2014/1/29/   最近刚开始学hash,名字很陌生,但是hash的思想却很熟悉,以前早就做过此类的题,但是不知道这就是hash思想而已,说白了hash就是一个映射,往往灵活利用数组的下标来实现算法,hash的作用:1、判重;2、统计次数;

JAVA智听未来一站式有声阅读平台听书系统小程序源码

智听未来,一站式有声阅读平台听书系统 🌟&nbsp;开篇:遇见未来,从“智听”开始 在这个快节奏的时代,你是否渴望在忙碌的间隙,找到一片属于自己的宁静角落?是否梦想着能随时随地,沉浸在知识的海洋,或是故事的奇幻世界里?今天,就让我带你一起探索“智听未来”——这一站式有声阅读平台听书系统,它正悄悄改变着我们的阅读方式,让未来触手可及! 📚&nbsp;第一站:海量资源,应有尽有 走进“智听

零基础学习Redis(10) -- zset类型命令使用

zset是有序集合,内部除了存储元素外,还会存储一个score,存储在zset中的元素会按照score的大小升序排列,不同元素的score可以重复,score相同的元素会按照元素的字典序排列。 1. zset常用命令 1.1 zadd  zadd key [NX | XX] [GT | LT]   [CH] [INCR] score member [score member ...]

【机器学习】高斯过程的基本概念和应用领域以及在python中的实例

引言 高斯过程(Gaussian Process,简称GP)是一种概率模型,用于描述一组随机变量的联合概率分布,其中任何一个有限维度的子集都具有高斯分布 文章目录 引言一、高斯过程1.1 基本定义1.1.1 随机过程1.1.2 高斯分布 1.2 高斯过程的特性1.2.1 联合高斯性1.2.2 均值函数1.2.3 协方差函数(或核函数) 1.3 核函数1.4 高斯过程回归(Gauss

【学习笔记】 陈强-机器学习-Python-Ch15 人工神经网络(1)sklearn

系列文章目录 监督学习:参数方法 【学习笔记】 陈强-机器学习-Python-Ch4 线性回归 【学习笔记】 陈强-机器学习-Python-Ch5 逻辑回归 【课后题练习】 陈强-机器学习-Python-Ch5 逻辑回归(SAheart.csv) 【学习笔记】 陈强-机器学习-Python-Ch6 多项逻辑回归 【学习笔记 及 课后题练习】 陈强-机器学习-Python-Ch7 判别分析 【学

Java ArrayList扩容机制 (源码解读)

结论:初始长度为10,若所需长度小于1.5倍原长度,则按照1.5倍扩容。若不够用则按照所需长度扩容。 一. 明确类内部重要变量含义         1:数组默认长度         2:这是一个共享的空数组实例,用于明确创建长度为0时的ArrayList ,比如通过 new ArrayList<>(0),ArrayList 内部的数组 elementData 会指向这个 EMPTY_EL

系统架构师考试学习笔记第三篇——架构设计高级知识(20)通信系统架构设计理论与实践

本章知识考点:         第20课时主要学习通信系统架构设计的理论和工作中的实践。根据新版考试大纲,本课时知识点会涉及案例分析题(25分),而在历年考试中,案例题对该部分内容的考查并不多,虽在综合知识选择题目中经常考查,但分值也不高。本课时内容侧重于对知识点的记忆和理解,按照以往的出题规律,通信系统架构设计基础知识点多来源于教材内的基础网络设备、网络架构和教材外最新时事热点技术。本课时知识