Python C API:根据PyObject类型切换

7 投票
1 回答
5755 浏览
提问于 2025-04-16 00:17

我有一些代码是用来让Python和C++互相沟通的,运行得还不错,但每次看到这些代码我都觉得应该有更好的写法。在C++那边,有一种叫做“variant”的类型,可以处理一些固定的基本类型,比如整数、实数、字符串、变体的向量等等。我有一些代码是用Python的API把这些类型转换成对应的Python类型。看起来大概是这样的:

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

问题在于这些连锁的if-else语句。感觉应该用switch语句,或者用一个函数表或映射表,里面存放不同类型的创建函数,使用类型标识符作为键。换句话说,我想写成这样:

  return createFunMap[typeID(value)](value);

根据我对API文档的粗略了解,直接获取这里的“typeID”并不是很明显。我看到我可以这样做:

  PyTypeObject* type = value->ob_type;

这样似乎能快速获取类型信息,但我想知道最简单的方式是什么,以便将其与我关心的有限类型关联起来?

1 个回答

3

从某种意义上说,我觉得你已经回答了自己的问题。

在某个地方,你需要根据数据来选择功能。在C语言中,做到这一点的方法是使用函数指针。

你可以创建一个对象类型到函数的映射表……每个函数都有一个清晰定义的接口。

variant PyBoolToVariant(PyObject *value) {
    return value == Py_True;
}

Map<PyTypeObject*,variant* (PyObject*)> function_map;

function_map.add(PyBool, PyBoolToVariant);

现在你的makeVariant函数可以这样写。

variant makeVariant(PyObject *value) {
    return (*function_map.get(value->ob_type))(value);
}

最难的部分是正确写出Map对象的语法。此外,我假设你可以使用一个接受类型参数的Map对象(<PyTypeObject*, variant*(PyObject*))。

我可能没有完全搞对Map的第二种类型的语法。它应该是一个指向函数的指针,这个函数接受一个指针并返回一个指向变体的指针。

希望这些对你有帮助。

撰写回答