gh-139852: Add PyObject_GetDictPtr() function by vstinner · Pull Request #139854 · python/cpython

Can those users switch to PyObject_GenericGetDict, or be better served by a variant of PyObject_GenericGetDict that doesn't raise for the “no __dict__” case? Do they need a PyObject**?

It seems like PyObject** is needed.

SWIG generates code which writes into the PyObject **dict_ptr:

#if !defined(SWIG_PYTHON_SLOW_GETSET_THIS)
      PyObject **dictptr = _PyObject_GetDictPtr(inst);
      if (dictptr != NULL) {
        PyObject *dict = *dictptr;
        if (dict == NULL) {
          dict = PyDict_New();
          *dictptr = dict;
        }
        if (dict) {
          PyDict_SetItem(dict, SWIG_This(), swig_this);
        } else{
          Py_DECREF(inst);
          inst = 0;
        }
      }
#else
      if (PyObject_SetAttr(inst, SWIG_This(), swig_this) == -1) {
        Py_DECREF(inst);
        inst = 0;
      }
#endif

pybind11 also writes into the PyObject **dict_ptr:

    PyObject **dict_ptr = _PyObject_GetDictPtr(self);
    if (dict_ptr) {
        Py_CLEAR(*dict_ptr);
    }

Obviously, there are other usages which only read the dictionary. Example from pybind11:

    PyObject *&dict = *_PyObject_GetDictPtr(self);
    Py_VISIT(dict);