Wired365 Wired365 - 1 month ago 22
C++ Question

Python NamedTuple to C++ Struct

I have searched the internet for hours at this point. Does anyone know how to parse a namedtuple returned from a python function into a struct or just into separate variables. The part I am having trouble with is getting the data out of the returned pointer. I am calling a python function embedded in C++ using the PyObject_CallFunction() call and I don't know what to do once I have the PyObject* to the returned data.

I am using Python 2.7 for reference.

EDIT: I ended up moving all of the functionality I was trying to do in both Python and C++ to just Python for now. I will update in the near future about attempting the strategy suggested in the comments of this question.

Answer

I am calling a python function embedded in C++ using the PyObject_CallFunction() call and I don't know what to do once I have the PyObject* to the returned data.

A namedtuple is a tuple subclass that additionally exposes tuple elements as named attributes. This means that you can choose whether to access its data as obj[position] or obj.attribute. The latter is generally more readable, but the former combines well with tuple unpacking. In Python/C, it is probably easier to access it as tuple, since then you can use the convenience function PyArg_ParseTuple, as indicated in the comment.

To extract arbitrary attributes of an object (not necessarily a namedtuple), one would call PyObject_GetAttrString. Given an object describing, say, a point, extracting an attribute such as x might look like this:

PyObject *point = ...;  // assume we get a new reference to point
if (!point)
  return NULL;
PyObject *x = PyObject_GetAttrString(point, "x");
if (!x) {
  // obj.x raised, possibly because point is of a different type
  Py_DECREF(point);
  return NULL;
}
double x_val = PyFloat_AsDouble(x);
Py_DECREF(x);     // x not used below this line
if (x_val == --1 && PyErr_Occurred()) {
  // obj.x is not float or float-like
  Py_DECREF(point);
  return NULL;
}
Py_DECREF(point); // point not used below this line

The error checking and reference counting is quite tedious, but it can be mostly eliminated using guard classes or, better yet, using the classes written by others, such as Boost.Python.

Comments