在 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
代码。
包装和嵌入愚蠢对象的小例子可能如下所示(注意,我为此使用.c
,c++
有类似的步骤):
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-config
的python-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 对象的主要内容,如果未能解决你的问题,请参考以下文章
使用 SWIG 将 C++ 对象指针传递给 Python,而不是再次返回 C++
如何使用纯 Python 扩展 API (python3) 包装 C++ 对象?