Какова цель Py_DECREF и PY_INCREF?

Я просматривал руководство по определению "новых типов" в python, https://docs.python.org/2/extending/newtypes.html, и я не понимал цель использования Py_DECREF в этом фрагменте кода.

static PyObject *
Noddy_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
{
    Noddy *self;

    self = (Noddy *)type->tp_alloc(type, 0);
    if (self != NULL) {
        self->first = PyString_FromString("");
        if (self->first == NULL)
          {
            Py_DECREF(self);
            return NULL;
          }

        self->last = PyString_FromString("");
        if (self->last == NULL)
          {
            Py_DECREF(self);
            return NULL;
          }

        self->number = 0;
    }

    return (PyObject *)self;
}

Мое понимание подсчета ссылок неоднозначно, и любая помощь будет признательна.

2 ответа

Решение

Сборщик мусора CPython использует 'Подсчет ссылок', то есть он поддерживает список ссылок на объект. Если счетчик ссылок объекта падает до нуля, это означает, что сборщик мусора может безопасно освободить место для этого объекта.

Следовательно, когда мы определяем PyObjects, обязательно нужно явно вызывать Py_INCREF и Py_DECREF, которые увеличивают и уменьшают число ссылок объекта соответственно.

В этом случае Py_DECREF просто освободит память, выделенную с помощью tp-> alloc.

tp-> alloc устанавливает счетчик ссылок на 1. Py_DECREF уменьшает счетчик ссылок с 1 до 0; поскольку он находит счетчик ссылок равным 0, он вызывает соответствующие функции для освобождения памяти (в этом случае Noddy_dealloc).

Если функция Python C API возвращает NULL, что-то пошло не так; обычно устанавливается исключение (сохраняется в глобальной переменной).

Если вызывающая сторона снова возвращает NULL, исключение связывается в цепочку, следовательно, 'return NULL'.

Подсчет ссылок используется для управления памятью, python отслеживает количество "ссылок-владельцев" на объект. Когда для объекта создается новая "ссылка-владелец", счетчик ссылок должен быть увеличен, а когда ссылка-владелец заканчивается, счетчик ссылок необходимо уменьшить. Если счетчик ссылок падает до 0, объект освобождается.

C не имеет никаких языковых функций, чтобы делать это автоматически, поэтому это нужно делать вручную. Чтобы уменьшить количество операций инкремента и декрета, в API Python C есть концепции "заимствования" и "кражи" ссылок. Как правило, параметры заимствуют ссылки, а возвращаемые значения передают право собственности на ссылку. Однако есть несколько исключений, например процедуры для списков и кортежей.

tp_alloc создает новый объект с единственной ссылкой и передает право владения этой ссылкой вам. На удачном пути вы, в свою очередь, передаете право собственности на эту ссылку вызывающей стороне после завершения процесса построения.

но на несчастливых путях у вас есть частично сконструированный объект, от которого вам нужно избавиться, отсюда и вызовы Py_Decref.

Другие вопросы по тегам