为什么在C中返回Py_None之前需要Py_INCREF(Py_None)?

时间:2013-03-08 05:51:29

标签: python c reference-counting

为什么在C中返回Py_None之前需要Py_INCREF(Py_None),如下所示?

Py_INCREF(Py_None);
return Py_None;

如果省略Py_INCREF(Py_None),会发生什么?

2 个答案:

答案 0 :(得分:23)

缺少Py_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调用。

您可以在tutorial中测试复制示例,将Py_DECREF(Py_None)的调用添加到Noddy_name函数中,构建扩展并执行调用该方法的循环。


在一般情况下,引用计数0会导致程序以多种不同方式失败。

特别是python可以自由地重用已被解除分配的对象使用的内存,这意味着突然对对象的每个引用都可以成为对随机对象(或空内存位置)的引用,你可以看看像:

>>> None   #or whatever object that was deallocated
<ARandomObjectYouNeverSawBefore object at ...>

(实际上happened对我来说,当编写C扩展时。由于缺少对Py_INCREF的调用而在随机时间变成只读缓冲区的一些对象。

在其他情况下,可能会出现不同类型的错误,或者解释程序可能崩溃或发生段错​​误。

答案 1 :(得分:19)

Py_None实际上只是另一个Python对象,除非没有方法。

Python会计算对任何PyObject*的引用。如果它是字符串,整数或无,则无关紧要。

如果你没有增加引用计数,Python解释器最终会在引用计数达到0之后丢弃该对象,认为没有任何指向该对象的指针。这意味着下次尝试使用返回值执行某些操作时,您将跟随指向内存中无法保证保留Py_None的位置的指针(错误,奇怪值,分段错误等)

还有其他方法可以记住使用Py_INCREF(Py_None)

return Py_BuildValue("");

Py_RETURN_NONE;