3

I'm calling Python from C++, and trying to perform some data conversions.

For example, if I call the following Python function

def getAMap():
   data = {}
   data["AnItem 1"] = "Item value 1"
   data["AnItem 2"] = "Item value 2"
   return data

from C++ as:

PyObject *pValue= PyObject_CallObject(pFunc, NULL);

where pFunc is a PyObject* that points to the getAMap python function. Code for setting up pFunc omitted for clarity.

The returned pointer, pValue is a pointer to a (among other things) Python dictionary. Question is, how to get thh dictionary into a std::map on the C++ side as smoothly as possible?

I'm using C++ Builder bcc32 compiler that can't handle any fancy template code, like boost python, or C++11 syntax.

(Changed question as the python object is a dictionary, not a tuple)

Totte Karlsson
  • 1,261
  • 1
  • 20
  • 55
  • Just found a library that *makes it easy to convert Python objects (Python C API) to standard C++ datatypes* as it says [here](https://github.com/dubzzz/Py2Cpp#metaprogramming-serving-py-c-and-c-py). Looks like it might help you due to it also supports `std::map`. – Bee Apr 23 '18 at 20:09
  • Also, consider [tag:swig]. – Robᵩ Apr 23 '18 at 20:09
  • Rob, I'm using swig in fact. – Totte Karlsson Apr 23 '18 at 20:12
  • David; that library looks great, but I can't use it with this compiler unfortunately. – Totte Karlsson Apr 23 '18 at 20:44
  • i would use [PyTuple_GetItem](https://docs.python.org/2/c-api/tuple.html) and copy the values into a map. Or write a swig typemap that does it for you. – Thomas Apr 23 '18 at 20:49
  • Thanks Thomas. I'm new to swig and embedding of Python. I guess a typemap would do it, so looking into that. – Totte Karlsson Apr 23 '18 at 20:59
  • https://stackoverflow.com/questions/1842941/translating-python-dictionary-to-c – ssk Apr 23 '18 at 21:12
  • This question is linked to a question related to translating Python code for populating a dictionary, to C++. That is quite different from this question. Not sure why it was linked?? – Totte Karlsson Apr 24 '18 at 14:38
  • @TotteKarlsson The library actually is just one header file. If I didn't miss anything the `std::map` casting is no longer than about 100 lines of code. So maybe you can just use the concept of the library and adapt it for your compiler? – Bee Apr 24 '18 at 20:18

1 Answers1

1

It's pretty ugly, but I came up with this:

std::map<std::string, std::string> my_map;

// Python Dictionary object
PyObject *pDict = PyObject_CallObject(pFunc, NULL);

// Both are Python List objects
PyObject *pKeys = PyDict_Keys(pDict);
PyObject *pValues = PyDict_Values(pDict);

for (Py_ssize_t i = 0; i < PyDict_Size(pDict); ++i) {
    // PyString_AsString returns a char*
    my_map.insert( std::pair<std::string, std::string>(
            *PyString_AsString( PyList_GetItem(pKeys,   i) ),
            *PyString_AsString( PyList_GetItem(pValues, i) ) );
}
Major
  • 544
  • 4
  • 19