CPython 的 PyLong_FromLong(0L) 永远不会失败?
CPython's PyLong_FromLong(0L) never fails?
这段代码来自Python C-API reference:
item = PyLong_FromLong(0L);
if (item == NULL)
goto error;
假设解释器是CPython,Python0
对象的内存是, so what could go wrong there? Reading the source code for PyLong_FromLong
, for small-integer values it would immediately return get_small_int((sdigit)0L)
. The get_small_int
function is really very simple:
static PyObject *
get_small_int(sdigit ival)
{
assert(IS_SMALL_INT(ival));
PyThreadState *tstate = _PyThreadState_GET();
PyObject *v = (PyObject*)tstate->interp->small_ints[ival + NSMALLNEGINTS];
Py_INCREF(v);
return v;
}
第一行的断言不会失败,因为PyLong_FromLong
已经验证过了。 _PyThreadState_GET()
是一个宏,根据其定义旁边的 comment,is unsafe: it does not check for error and it can return NULL.
这可能看起来像是失败的根源,但 请注意 tstate->interp
是正常访问 ,如果宏返回 NULL
,这将导致解释器出现段错误。之后,对 Python 0
对象的引用被 Py_INCREF
返回给 PyLong_FromLong(0L)
.
的原始调用者
我是否正确理解了 CPython 的 PyLong_FromLong
不会因小整数参数而失败,还是我错过了什么?另外,为了完整起见,用 C 编写的扩展模块是否可以从其他解释器中使用,或者在编写它们时我可以假设它们将处理 CPython?
是的,你完全正确,这里永远不会有任何错误,小整数是预先分配的,所以 PyLong_FromLong(0L);
永远不会失败。
但为什么还要测试 item 是否为 NULL?如我所见,这只是一个部分:
- 新建一个 PyLongObject;
- 然后测试是否成功
PyLong_FromLong 通过缓存小整数进行了一些优化,但它仍然 returns 大部分和合乎逻辑地是一个新对象,尽管 0L 没有。作为函数调用者,我们不应该依赖内部缓存策略。所以留下一些代码来检查会更有意义也更安全。
这段代码来自Python C-API reference:
item = PyLong_FromLong(0L);
if (item == NULL)
goto error;
假设解释器是CPython,Python0
对象的内存是PyLong_FromLong
, for small-integer values it would immediately return get_small_int((sdigit)0L)
. The get_small_int
function is really very simple:
static PyObject *
get_small_int(sdigit ival)
{
assert(IS_SMALL_INT(ival));
PyThreadState *tstate = _PyThreadState_GET();
PyObject *v = (PyObject*)tstate->interp->small_ints[ival + NSMALLNEGINTS];
Py_INCREF(v);
return v;
}
第一行的断言不会失败,因为PyLong_FromLong
已经验证过了。 _PyThreadState_GET()
是一个宏,根据其定义旁边的 comment,is unsafe: it does not check for error and it can return NULL.
这可能看起来像是失败的根源,但 请注意 tstate->interp
是正常访问 ,如果宏返回 NULL
,这将导致解释器出现段错误。之后,对 Python 0
对象的引用被 Py_INCREF
返回给 PyLong_FromLong(0L)
.
我是否正确理解了 CPython 的 PyLong_FromLong
不会因小整数参数而失败,还是我错过了什么?另外,为了完整起见,用 C 编写的扩展模块是否可以从其他解释器中使用,或者在编写它们时我可以假设它们将处理 CPython?
是的,你完全正确,这里永远不会有任何错误,小整数是预先分配的,所以 PyLong_FromLong(0L);
永远不会失败。
但为什么还要测试 item 是否为 NULL?如我所见,这只是一个部分:
- 新建一个 PyLongObject;
- 然后测试是否成功
PyLong_FromLong 通过缓存小整数进行了一些优化,但它仍然 returns 大部分和合乎逻辑地是一个新对象,尽管 0L 没有。作为函数调用者,我们不应该依赖内部缓存策略。所以留下一些代码来检查会更有意义也更安全。