Python C API: Switch on PyObject type
I have some code to interface Python to C++ which works fine but every time I look at it I think there must be a better way to do it. On the C++ side there is a 'variant' type that can deal with a fixed range of basic types - int, real, string, vector of variants, etc. I have some code using the Python API to convert from the equivalent Python types. It looks something like this:
variant makeVariant(PyObject* value)
{
if (PyString_Check(value)) {
return PyString_AsString(value);
}
else if (value == Py_None) {
return variant();
}
else if (PyBool_Check(value)) {
return value == Py_True;
}
else if (PyInt_Check(value)) {
return PyInt_AsLong(value);
}
else if (PyFloat_Check(value)) {
return PyFloat_AsDouble(value);
}
// ... etc
The problem is the chained if-else ifs. It seems to be calling out for a switch statement, or a tab开发者_如何学Gole or map of creation functions which is keyed by a type identifier. In other words I want to be able to write something like:
return createFunMap[typeID(value)](value);
Based on a skim of the API docs it wasn't obvious what the best way is to get the 'typeID' here directly. I see I can do something like this:
PyTypeObject* type = value->ob_type;
This apparently gets me quickly to the type information but what is the cleanest way to use that to relate to the limited set of types I am interested in?
In a way, I think you've answered your own question.
Somewhere, you're going to have to select functionality based on data. The way to do this in C is to use function pointers.
Create a map of object_type->function mappers... where each function has a clearly-defined interface.
variant PyBoolToVariant(PyObject *value) {
return value == Py_True;
}
Map<PyTypeObject*,variant* (PyObject*)> function_map;
function_map.add(PyBool, PyBoolToVariant);
Now your makeVariant can look like this.
variant makeVariant(PyObject *value) {
return (*function_map.get(value->ob_type))(value);
}
The hard part is going to be getting the syntax right for the Map object. Also, I'm assuming there is a Map object you can use that takes type parameters (<PyTypeObject*, variant*(PyObject*)
).
I probably have not quite gotten the syntax correct for the second type of the Map. It should be a pointer to a function which takes one pointer and returns a pointer to a variant.
I hope this is helpful.
精彩评论