为什么在 C 中返回 Py_None 之前需要 Py_INCREF(Py_None),如下所示?
Py_INCREF(Py_None);
return Py_None;
如果 Py_INCREF(Py_None) 被省略,会发生什么?
为什么在 C 中返回 Py_None 之前需要 Py_INCREF(Py_None),如下所示?
Py_INCREF(Py_None);
return Py_None;
如果 Py_INCREF(Py_None) 被省略,会发生什么?
缺少 aPy_INCREF
将导致对 的引用计数不正确Py_None
,这可能导致解释器解除分配Py_None
。由于是在文件Py_None
中静态分配的:Objects/object.c
PyObject _Py_NoneStruct = {
_PyObject_EXTRA_INIT
1, &PyNone_Type
};
里面有Include/object.h
定义:
#define Py_None (&_Py_NoneStruct)
那么会发生什么,解释器将因致命错误而崩溃:
Fatal Python error: deallocating None
由以下none_dealloc
函数生成Objects/object.c
:
/* ARGUSED */
static void
none_dealloc(PyObject* ignore)
{
/* This should never get called, but we also don't want to SEGV if
* we accidentally decref None out of existence.
*/
Py_FatalError("deallocating None");
}
正如该评论所述,如果NoneType
没有自己的解除分配功能,您将获得分段错误,因为free
将在堆栈上完成调用。
您可以复制教程Py_DECREF(Py_None)
中的示例,在函数中添加调用Noddy_name
,构建扩展并执行循环调用该方法。
在一般情况下,引用计数0
会导致程序以许多不同的方式失败。
特别是 python 可以自由地重用被释放的对象使用的内存,这意味着突然对对象的每个引用都可以成为对随机对象(或空内存位置)的引用,你可以看到类似:
>>> None #or whatever object that was deallocated
<ARandomObjectYouNeverSawBefore object at ...>
(这实际上有时发生在我身上,在编写 C 扩展时。由于缺少对 的调用,一些对象在随机时间变成只读缓冲区Py_INCREF
)。
在其他情况下,可能会引发不同类型的错误,或者解释器可能会崩溃或段错误。
Py_None
实际上只是另一个 Python 对象,除了没有方法。
Python 将计算对任何PyObject*
. 它是字符串、整数还是 None 都没有关系。
如果不增加引用计数,Python 解释器最终会在引用计数达到 后丢弃该对象0
,认为没有任何指向该对象的指针。这意味着下次您尝试对返回值做某事时,您将跟随一个指向内存中不能保证保存的位置的指针Py_None
(错误、奇怪的值、分段错误等)。
除了必须记住使用之外,还有其他选择Py_INCREF(Py_None)
:
return Py_BuildValue("");
或者
Py_RETURN_NONE;