Зачем нужно Py_INCREF (Py_None) перед возвратом Py_None в C следующим образом?
Py_INCREF(Py_None);
return Py_None;
Если Py_INCREF (Py_None) опущен, что произойдет?
Зачем нужно Py_INCREF (Py_None) перед возвратом Py_None в C следующим образом?
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
будет выполнен в стеке.
Вы можете протестировать это копирование примера в учебник, добавив вызов Py_DECREF(Py_None)
в функцию Noddy_name
, создайте расширение и сделать цикл, вызывающий этот метод.
В общем случае счетчик ссылок 0
может привести к сбою программы разными способами.
В частности, python может повторно использовать память, используемую объектами, которые были освобождены, что означает, что внезапно каждая ссылка на объект может стать ссылкой на случайный объект (или на пустую ячейку памяти), и вы могли бы см. такие вещи, как:
>>> None #or whatever object that was deallocated
<ARandomObjectYouNeverSawBefore object at ...>
В других ситуациях могут возникать различные ошибки, или интерпретатор может сбой или segfault.
Py_None
- это действительно еще один объект Python, за исключением без методов.
Python будет считать ссылки на любой PyObject*
. Не имеет значения, является ли это строкой, целым числом или None.
Если вы не увеличиваете счетчик ссылок, интерпретатор Python в конечном итоге отбросит объект после того, как его счетчик ссылок достигнет 0
, считая, что нет никаких указателей на объект. Это означает, что в следующий раз, когда вы попытаетесь что-то сделать с возвращаемым значением, вы будете следовать указателю на место в памяти, в котором не гарантируется сохранение Py_None
(ошибка, странное значение, ошибка сегментации и т.д.).
Есть альтернативы необходимости запоминать использование Py_INCREF(Py_None)
:
return Py_BuildValue("");
или
Py_RETURN_NONE;