Uh oh!
There was an error while loading.Please reload this page.
- Notifications
You must be signed in to change notification settings - Fork32k
Description
The PyDict C API has a bad history. PyDict_GetItem() ignores all exception: error on hash(), error on "key == key2", KeyboardInterrupt, etc. PyDict_GetItemWithError() was added to fix this design. Moreover, Python 3.9 and older allowed to call PyDict_GetItem() with the GIL released.
PyDict_GetItem() returns a borrowed reference which is usually safe since the dictionary still contains a strong reference to the request value. But in general, borrowed references are error prone and can likely lead to complex race conditions causing crashes:
- "Functions must not return borrowed references" sayshttps://devguide.python.org/developer-workflow/c-api/index.html
- Unclear lifetimes of borrowed references capi-workgroup/problems#5
WhilePyDict_GetItem()
calls can be quite easily replaced withPyObject_GetItem()
which has a better API (return a new stong reference), developers usually prefer to still use the specialized PyDict API for best performance: avoid the minor overhead of type dispatching,Py_TYPE(obj)->tp_as_mapping->mp_subscript
.
I propose addingPyDict_GetItemRef()
andPyDict_GetItemStringRef()
functions to the limited C API (version 3.13): replacements forPyDict_GetItem()
,PyDict_GetItemWithError()
andPyDict_GetItemString()
.
API:
int PyDict_GetItemRef(PyObject *mp, PyObject *key, PyObject **pvalue);int PyDict_GetItemStringRef(PyObject *mp, const char *key, PyObject **pvalue);
PyDict_GetItemWithError()
has another API issue: when it returns NULL, it can mean two things. It returns NULL if the key is missing, but it also returns NULL on error. The caller has to checkPyErr_Occurred()
to distinguish the two cases (to write correct code). Seecapi-workgroup/problems#1 Proposed API avoids this by returning anint
: return -1 on error, or return 0 otherwise (present or missing key). CheckingPyErr_Occurred()
is no longer needed.
By the way, the public C API has no PyDict_GetItemStringWithError() function: usingPyDict_GetItemWithError()
with achar*
key is not convenient. The_PyDict_GetItemStringWithError()
function exists but it's a private C API.