爲什麼在返回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