Python C API - PyDict - 值和键是否需要引用计数?

Python C API - PyDict - Do values and keys need to be reference counted?

我有一些代码在内部使用 PyDict 来存储数据。用户像使用普通 python 字典一样设置数据,数据由 C 代码存储在 PyDict 对象中。我的问题是:我需要引用计数 (Py_INCREF) 值和键吗?只是价值? documentation 表示调用 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;
}

至于 destructor/deallocator,我假设我只需要手动迭代 dict 并递减值(也许还有键?)除非有更好的方法吗? (要清楚,我的意思是在 tp_dealloc 函数中)

您不需要在此处执行任何引用计数处理。 dict 拥有它持有的所有引用,并且它将管理 incref/decref 调用。您不拥有任何正在创建或销毁的引用。您也不需要调用 PyDict_GetItem.

您的解除分配器也是如此。您只拥有对字典本身的引用,而不是字典对其内容的引用。你只需要减少字典。字典将处理其内容。