#python #python-c-api #python-extensions
Вопрос:
Я читал этот учебник, чтобы узнать, как написать модуль расширения C для определения новых типов. В какой-то момент tp_init
была дана следующая реализация:
static int
Custom_init(CustomObject *self, PyObject *args, PyObject *kwds)
{
static char *kwlist[] = {"first", "last", "number", NULL};
PyObject *first = NULL, *last = NULL, *tmp;
if (!PyArg_ParseTupleAndKeywords(args, kwds, "|OOi", kwlist,
amp;first, amp;last,
amp;self->number))
return -1;
if (first) {
tmp = self->first;
Py_INCREF(first);
self->first = first;
Py_XDECREF(tmp);
}
if (last) {
tmp = self->last;
Py_INCREF(last);
self->last = last;
Py_XDECREF(tmp);
}
return 0;
}
Проблема, с которой я сталкиваюсь, заключается в том, что я не вижу никакого вреда в том, чтобы назначить первого участника таким образом:
if (first) {
Py_XDECREF(self->first);
Py_INCREF(first);
self->first = first;
}
С другой стороны, упомянутый учебник предостерегает нас от его использования, потому что:
Наш тип не ограничивает тип первого элемента, поэтому это может быть любой объект. У него может быть деструктор, который вызывает выполнение кода, пытающегося получить доступ к первому члену
Далее в нем также говорится::
Чтобы быть параноиком и защититься от такой возможности, мы почти всегда переназначаем участников, прежде чем уменьшать их количество ссылок
Принимая во внимание эти предупреждения, я все еще не вижу никаких практических различий между этими двумя способами. Итак, почему я должен использовать первый, который переназначает участника first
новому PyObject, прежде чем уменьшать количество ссылок на старый PyObject?
Комментарии:
1. Я попытался ответить на этот вопрос, но в итоге удалил его, потому что я просто повторял документацию. Возможно, вы упускаете деталь, которая
Py_XDECREF
может привести к выполнению произвольного кода Python, и функция C не будет выполняться до тех пор, пока этот код Python не завершит выполнение?2. Я полагаю, что произвольный код Python, на который вы ссылаетесь, не будет выполняться до тех пор, пока не включится сборщик мусора и количество ссылок PyObject не достигнет нуля. Чего я не могу понять, так это того, как рекомендуемый способ позволяет нам избежать этой проблемы по сравнению с не рекомендуемым способом?
3. Количество ссылок на объекты может достигать 0 при любом уменьшении. «Сборщик мусора» — это отдельная функция, которая иногда запускается для поиска циклических ссылок.