为什么在返回Py_None之前需要Py_INCREF(Py_None),如下所示?为什么在返回Py_None之前需要Py_INCREF(Py_None)?
Py_INCREF(Py_None);
return Py_None;
如果省略Py_INCREF(Py_None),会发生什么情况?
为什么在返回Py_None之前需要Py_INCREF(Py_None),如下所示?为什么在返回Py_None之前需要Py_INCREF(Py_None)?
Py_INCREF(Py_None);
return Py_None;
如果省略Py_INCREF(Py_None),会发生什么情况?
如果缺少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
随机倍)。
在其他情况下,可能会引发不同类型的错误,或解释器可能崩溃或段错误。
Py_None
实际上只是另一个Python对象,除非没有方法。
Python会计算对任何PyObject*
的引用。无论它是字符串,整数还是无。
如果不增加引用计数,Python解释器会在其引用计数达到0
后最终放弃该对象,因为它认为没有任何指向该对象的指针。这意味着下一次您尝试使用返回值执行某些操作时,您将会看到一个指向内存中的位置的指针,该位置不保证为Py_None
(错误,奇怪的值,分段错误等)。
有替代品必须记住使用Py_INCREF(Py_None)
:
return Py_BuildValue("");
或
Py_RETURN_NONE;
'PyNone'可能是静态分配(不Python源我来看看它),所以我们试着释放静态分配的内存,这将是特别有趣的..在任何情况下都没有什么好处。 – Voo 2013-03-08 08:05:02
@Voo我也这么认为,事实证明它是静态分配的(在'object.c'中),这导致了一个致命的错误。无论如何,我的推理是正确的,只是它更适合忘记增加一个通用对象。 – Bakuriu 2013-03-08 10:57:01