在 C++ 中使用 Python 对象

Posted

技术标签:

【中文标题】在 C++ 中使用 Python 对象【英文标题】:Using Python objects in C++ 【发布时间】:2016-06-01 19:56:08 【问题描述】:

我正在编写一个代码,它使用区间分析的方法计算非线性地图的图像,应用 minkowski 和并重复任意次数的迭代。

我已经用 Python 编写了一个工作代码,但是我希望能够在 C++ 中实现算法的一些迭代/递归密集型部分,以从提高的速度中受益。我过去使用过 Cython 并取得了很好的效果,但我想练习我的 C++。

另外,我的对象非常复杂,我宁愿避免在 C++ 中实现它们(小步骤!)。

所以我的问题是:

1) 会妨碍效率的提高吗?

2) 如果没有,是否可以使用 Cython 包装一个 C++ 函数,该函数在 python 对象上进行迭代/递归?

更具体地说,我有一个递归算法,它在 BST 的左右子节点上进行递归(尽管它是一个经过大量修改的 BST,所以我不想陷入在 C++ 中实现它的细节中) ,但是运行时非常令人望而却步,所以我想用 C++ 编写它。

【问题讨论】:

如果你打算用 C++ 重写 Python 代码,那么你将一无所获。但是您可以从 Python 对象中提取数据并在纯 C++ 上进行操作,这肯定会给您带来巨大的性能提升,主要是因为您可以放弃繁重的多态性。 那么,本质上你想实现Python中的数据结构并实现作用于DS的算法是C++,对吧? @Jim 就是这个主意:) 【参考方案1】:

是的。您将获得比纯 python 更快的速度,但与使用纯 C/C++ 时所获得的速度不相上下。如果你想处理 Python 对象,你需要通过Python C/API 来完成;这增加了执行的开销,你必须为被允许与 Python 交互而付出的代价。

请注意,这涉及很多复杂性,因为您需要熟悉 API 并阅读函数对对象引用的作用、如何创建列表、打包元组等。如果您只创建几个 public Cython cdef 函数来包装对象上的方法,则可以跳过所有这些。这会生成为您处理这些的所有CPython 代码。

包装和嵌入愚蠢对象的小例子可能如下所示(注意,我为此使用.cc++ 有类似的步骤):

class PyClass(object):

    def __init__(self):
        self.data = []

    def add(self, val):
        self.data.append(val)

    def __str__(self):
        return "Data: " + str(self.data)

cdef public object createPyClass():
    return PyClass()

cdef public void addData(object p, int val):
    p.add(val)

cdef public char* printCls(object p):
    return bytes(str(p), encoding = 'utf-8')

使用cython pycls.pyx 编译(使用--cplus 表示c++)将生成分别包含源和函数声明的.c.h 文件。您现在需要做的就是创建一个启动 Python 的main.c 文件,然后您就可以调用这些函数了:

#include "Python.h"   // Python.h always gets included first.
#include "pycls.h"    // Include your header file.

int main(int argc, char *argv[])

    Py_Initialize();   // initialize Python
    PyInit_pycls();    // initialize module (initpycls(); in Py2)
    PyObject *obj = createPyClass();
    for(int i=0; i<10; i++)
        addData(obj, i);
    
    printf("%s\n", printCls(obj));
    Py_Finalize();
    return 0;

使用适当的标志编译它(您可以从python3.5-configpython-config [Py2] 获得):

gcc pycls.c main.c -L$(python3.5-config --cflags) -I$(python3.5-config --ldflags) -std=c99

将创建与您的对象交互的可执行文件:

./a.out
Data: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

所有这些都是通过使用Cython 以及生成.h 头文件的public 关键字来完成的。您也可以使用 Cython 编译一个 python 模块并自己创建头文件/处理额外的样板。由于我认为您不想在 C-API 学习中陷入困境,所以这不应该是要走的路。

正如@freakish 在他的评论中所说,提取数据 (numpy has a C-API you can use for this) 并在纯 C++ 中处理它是理想的。一般来说,如果你在C/C++ 中工作循环并在那里执行繁重的工作,你会得到很好的加速。

【讨论】:

谢谢。我同意,花在学习 API 上的努力可能不值得我花时间。提取数据似乎是个好主意。我昨晚决定,如果我要认真致力于学习这门语言,我也会尝试用 C++ 重写我的课程。如果碰巧我无法管理它,我会研究数据提取。

以上是关于在 C++ 中使用 Python 对象的主要内容,如果未能解决你的问题,请参考以下文章

在 C++ 中创建对象并将指针传递给 python

使用 SWIG 将 C++ 对象指针传递给 Python,而不是再次返回 C++

如何在python中控制c++类对象?

如何使用纯 Python 扩展 API (python3) 包装 C++ 对象?

Boost.Python 从 C++ 创建对现有 Python 对象的新引用

如何在 Cython 中将 Python 对象转换为 C++ 类型