Muhammad Sadiq Alvi
Muhammad Sadiq Alvi

Reputation: 1099

CPython - Read Python Dictionary (keys/values) inside a C Function Passed as argument

I am writing a Python C extension. I am passing a Python dict to a C function. I am able to parse it, using the following code:

PyObject *large_dict = NULL;
if (!PyArg_ParseTuple(args, "O!", &PyDict_Type, &large_dict)) return NULL;
if (large_dict != NULL)
{
   printf("Large Dictionary Not Null\n");
}

Here the statement "Large Dictionary Not Null" is printed, which means that the dictionary is parsed successfully. Now I want to access the dictionary values by specifying keys, like we do in Python. For example, large_dict['k1'] would give value v1.

How can I access dictionary keys/values inside this C function?

Upvotes: 7

Views: 6465

Answers (2)

Moot
Moot

Reputation: 2382

I'll reply for Python 3.7+, since that's the most likely use case these days (see reference). Converting from/to C types is dependent on the Python type of the keys/values, which you haven't specified. For the sake of illustrating an actual use-case, let's assume the keys and values are both positive integers. Then if you want to retrieve the value for k1=42 then I think you can do this:

   unsigned int k1 = 42;
   PyObject *py_k1 = PyLong_FromUnsignedLong(k1);
   PyObject *py_v1 = PyDict_GetItem(large_dict, py_k1);
   unsigned int v1 = PyLong_AsUnsignedLong(py_v1);

Breaking this down line by line, the first line defines the key as a plain C unsigned int. But we can't use a regular C type to index into a Python dict, therefore in the second line we define a pointer to a Python type that will point to the key. We then do the C equivalent of Python's large_dict[k1] via PyDict_GetItem, but using the pointer we created as the key and obtaining a pointer to a Python type as the value. Finally, if we want to access the value as a regular C type, we need to convert it in the last line, which is the reverse of what we did in the second line.

Note: PyDict_GetItem returns a borrowed reference, so we don't need to worry about reference counting.

Upvotes: 0

Aashish P
Aashish P

Reputation: 1966

You should go through the link, https://docs.python.org/2/c-api/dict.html Excerpt given below,

PyObject* PyDict_GetItem(PyObject *p, PyObject *key)
Return value: Borrowed reference.
Return the object from dictionary p which has a key key. Return NULL if the key key is not present, but without setting an exception.

PyObject* PyDict_GetItemString(PyObject *p, const char *key)
Return value: Borrowed reference.
This is the same as PyDict_GetItem(), but key is specified as a char*, rather than a PyObject*.

PyObject* PyDict_Items(PyObject *p)
Return value: New reference.
Return a PyListObject containing all the items from the dictionary, as in the dictionary method dict.items().

PyObject* PyDict_Keys(PyObject *p)
Return value: New reference.
Return a PyListObject containing all the keys from the dictionary, as in the dictionary method dict.keys().

PyObject* PyDict_Values(PyObject *p)
Return value: New reference.
Return a PyListObject containing all the values from the dictionary p, as in the dictionary method dict.values().

Keep an eye on borrowed reference / new reference. It is little tricky while coding for Python extensions.

Upvotes: 5

Related Questions