Python C API:打开 PyObject 类型

发布于 2024-09-06 17:35:30 字数 925 浏览 7 评论 0 原文

我有一些将 Python 与 C++ 接口的代码,工作得很好,但每次我看到它时,我都认为一定有更好的方法来实现。在 C++ 方面,有一个“变体”类型,可以处理固定范围的基本类型 - int、real、string、变体向量等。我有一些代码使用 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 if。它似乎正在调用 switch 语句,或者由类型标识符作为键的创建函数的表或映射。换句话说,我希望能够编写如下内容:

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

根据 API 文档的浏览,直接获取“typeID”的最佳方法是什么并不明显。我发现我可以做这样的事情:

  PyTypeObject* type = value->ob_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 table 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?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

节枝 2024-09-13 17:35:30

在某种程度上,我认为你已经回答了你自己的问题。

在某些地方,您将必须根据数据选择功能。在 C 语言中实现这一点的方法是使用函数指针。

创建一个 object_type->function 映射器的映射...其中每个函数都有一个明确定义的接口。

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 对象 ()。

我可能还没有完全掌握第二种类型的地图的正确语法。它应该是一个指向函数的指针,该函数接受一个指针并返回一个指向变体的指针。

我希望这有帮助。

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.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文