python - 如何仅使用 c/python api 将 c++ 成员函数绑定(bind)到 python?

标签 python c++

我使用 c/python api 将我的类绑定(bind)到 python。 我制作了新模块并成功绑定(bind)了类类型。 c/python api 具有 PyMethodDef 结构来将函数绑定(bind)到 python 类。

PyMethodDef pyMethodDef = { "PyFunction", PYFunction, METH_KEYWORDS | 
METH_VARARGS  , "PyFunction" };

PyObject *pFunc = PyCFunction_New(&pyMethodDef, NULL);
PyObject *pMethod = PyInstanceMethod_New(pFunc);
int result = PyDict_SetItemString(pPyClassDict, pyMethodDef.ml_name, 
 pMethod);

但是,有一个糟糕的规则,绑定(bind)函数必须有 PyObject* 返回类型,并且它必须有 2 个 PyObject* 参数。

PyObject* PYFunction(PyObject* self, PyObject* args)
{
    char *s = "Hello from C!";
    return Py_BuildValue("s", s);
}

所以我不能像这样绑定(bind)我的类和成员函数。

class Position
{
   int x;
   int y;
  public:
   Position() {x = 0; y = 0}
   ~Potition() { }+
   void SetZero()
   {
      x = 0, y = 0
   }
}

像下面这样改变所有成员函数的签名是不可能的。 因为实际上我有很多类要绑定(bind)。

PyObject* method(PyObject*, PyObject*)

那么 boost python 将是一个解决方案,但它太大而无法使用。 我只需要 python binder,它太难用了。

有什么方法可以仅使用纯 c/python api 将 c++ 成员函数(方法)绑定(bind)到 python 吗? (PyMethodDef 结构的第二个成员是 PyCFunction 类型...)

最佳答案

要使简单的包装器快速工作,同时只需编写很少的胶水,那么 SWIG 是您的最佳选择。

假设你想包装example.{h,cpp},通常你需要写的是:

/* File: example.i */
%module example

%{
#define SWIG_FILE_WITH_INIT
#include "example.h"
%}
%include example.h
  • %module example 告诉 SWIG 生成一个名为“example”的模块
  • #include "example.h" 使您的 C++ 函数定义在 example.i
  • 中可用
  • %include example.h 告诉 SWIG 导出它直接在 example.h 中找到的每个函数和类定义。

然后运行:

swig -c++ -python example.i # generates example.py and example_wrap.cxx
g++ -c -fPIC example.cxx
g++ -c -fPIC example_wrap.cxx -I /usr/include/python3.5
g++ -shared example.o example_wrap.o -o _example.so

你就完成了。 (作为引用,我使用的是 python 3.5 和 SWIG 3.0)

函数重载

一个常见的陷阱是,如果您有 SWIG 无法消除歧义的重载函数(例如,它们重载整数类型 [foo(int) vs foo(short)], float 点类型,或指针与引用 [Foo*Foo&])。您可以在 example.i 中添加忽略或重命名指令,以帮助它了解要忽略哪些函数或如何公开它们。

例如,给定:

/* File: example.h */

int add(int a, int b);
short add(short a, short b);
long long add(long long a, long long b);
double add(double a, double b);

您可以将以下内容添加到您的example.i:

%ignore add(short, short);
%rename("add_long_long") add(long long, long long);

然后你可以像这样使用它:

>>> import example
>>> example.add(1, 2)  # add(int, int)
3
>>> example.add(1.5, 2)  # add(double, double)
3.5
>>> example.add_long_long(1, 2)  # add(long, long)
3
>>> example.add_long_long(1 << 30, 1 << 30)  # add(long, long)
2147483648
>>> example.add(1 << 30, 1 << 30)  # add(int, int)
-2147483648

关于python - 如何仅使用 c/python api 将 c++ 成员函数绑定(bind)到 python?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50561318/

相关文章:

python - 如何控制外部可执行应用程序?

python - 传播计算结果

python - MLP分类器: "ValueError: Unknown label type"

python - 删除 kivy 文本输入边界

c++ - 具有隐藏可见性的 C++ 模板参数问题

c++ - 计算累积直方图

c++ - 无法删除类的析构函数中指向数组的成员指针

c++ - boost 的 dijkstra_shortest_paths 中的负边权重检查

python - tshark 和 powershell 重定向如何创建字节码文本文件?

c++ - 在线 C++ 标准草案的更新是否会使指向它的链接失效?