У меня есть код, который использует PyDict для хранения данных. Пользователь устанавливает данные так же, как в обычном словаре Python, и данные сохраняются кодом C в объекте PyDict. Мой вопрос таков: нужно ли мне подсчитывать ссылки (Py_INCREF) на значение И ключ? Только ценность? В документации указано, что вызов PyDict_SetItem НЕ крадет ссылку на значение. Насколько я понимаю, это означает, что объект PyDict не отвечает за значение PyObject, поэтому счетчик ссылок необходимо увеличить. В документах не упоминается ключ - нужно ли его также увеличивать?
Связанный с этим вопрос касается делокатора для моего кода - эти счетчики ссылок необходимо очистить - есть ли какой-либо «краткий путь» для повторения итераций в C API и уменьшения всех ссылок, или мне нужно будет вручную перебирать объект PyDict и уменьшить все значения по отдельности (и, возможно, ключи, в зависимости от ответа на вышеизложенное?)
Рассматриваемый код будет выглядеть примерно так (с вопросами в комментариях):
int myobject_setitem(myobject *self, PyObject *key, PyObject *value) {
if (value) {
Py_INCREF(key); // <--- is this needed?
Py_INCREF(value);
return PyDict_SetItem(self->data, key, value);
}
/* I assume I need to look up the value so I can decrement the reference count
before removing it from the dictionary, right? */
PyObject *value = PyDict_GetItem(self->data, key);
if (!value) {
return -1;
}
int ret = PyDict_DelItem(self->data, key);
Py_DECREF(key); // <------- is this needed?
Py_DECREF(value);
return ret;
}
Что касается деструктора/деаллокатора, я предполагаю, что мне просто нужно выполнить итерацию по dict вручную и уменьшить значения (и, возможно, ключи?), Если нет лучшего способа? (Чтобы было ясно, я имею в виду функцию tp_dealloc)
Вам не нужно выполнять здесь какую-либо обработку счетчика ссылок. Дикту принадлежат все имеющиеся у него ссылки, и он будет управлять вызовами incref/decref. Вы не являетесь владельцем ни одной из создаваемых или уничтожаемых ссылок. Вам также не нужно вызывать PyDict_GetItem.
То же самое касается вашего делокатора. Вы владеете только ссылкой на сам словарь, а не ссылками на его содержимое. Вам нужно только расшифровать dict. Диктатор будет обрабатывать его содержимое.
@Bryant: У тебя все наоборот. Если PyDict_SetItem украл ссылки, вам нужно будет выполнить вызовы incref (поскольку вы не владеете ссылками key
или value
— они заимствованы — поэтому вам нужно будет создать новые ссылки для кражи).
Вы действительно правы, нужно было более внимательно прочитать документы - спасибо!
Значит, я совершенно неправильно понял терминологию? В документах указано, что ссылка не украдена, значит ли это, что новой ссылки нет? Если рассматриваемый объект выходит за пределы области действия вызывающей стороны, он не будет собирать мусор из-под словаря?