Python 编程/使用 C++ 扩展
外观
有不同的方法可以使用 C 和 C++ 代码扩展 Python
- 使用纯 C,使用 Python.h
- 使用 Swig
- 使用 Boost.Python,可选择使用 Py++ 预处理
- 使用 pybind11
- 使用 Cython.
本页描述 Boost.Python。在 Cython 出现之前,它是编写 C++ 扩展模块最舒适的方式。
Boost.Python 与 Boost C++ 库捆绑在一起。要在 Ubuntu 系统上安装它,您可能需要运行以下命令
$ sudo apt-get install libboost-python-dev $ sudo apt-get install python-dev
#include <iostream>
using namespace std;
void say_hello(const char* name) {
cout << "Hello " << name << "!\n";
}
#include <boost/python/module.hpp>
#include <boost/python/def.hpp>
using namespace boost::python;
BOOST_PYTHON_MODULE(hello)
{
def("say_hello", say_hello);
}
#!/usr/bin/env python
from distutils.core import setup
from distutils.extension import Extension
setup(name="PackageName",
ext_modules=[
Extension("hello", ["hellomodule.cpp"],
libraries = ["boost_python"])
])
现在我们可以使用以下命令构建我们的模块
python setup.py build
模块 `hello.so` 将最终位于例如 `build/lib.linux-i686-2.4` 中。
更改到包含文件 `hello.so` 的子目录。在交互式 Python 会话中,您可以按如下方式使用该模块。
>>> import hello >>> hello.say_hello("World") Hello World!
CGAL 库的一些(但不是全部)函数已经有了 Python 绑定。这里提供了一个没有这种绑定的案例以及如何实现它的示例。该示例取自 CGAL 文档.
// test.cpp
using namespace std;
/* PYTHON */
#include <boost/python.hpp>
#include <boost/python/module.hpp>
#include <boost/python/def.hpp>
namespace python = boost::python;
/* CGAL */
#include <CGAL/Cartesian.h>
#include <CGAL/Range_segment_tree_traits.h>
#include <CGAL/Range_tree_k.h>
typedef CGAL::Cartesian<double> K;
typedef CGAL::Range_tree_map_traits_2<K, char> Traits;
typedef CGAL::Range_tree_2<Traits> Range_tree_2_type;
typedef Traits::Key Key;
typedef Traits::Interval Interval;
Range_tree_2_type *Range_tree_2 = new Range_tree_2_type;
void create_tree() {
typedef Traits::Key Key;
typedef Traits::Interval Interval;
std::vector<Key> InputList, OutputList;
InputList.push_back(Key(K::Point_2(8,5.1), 'a'));
InputList.push_back(Key(K::Point_2(1.0,1.1), 'b'));
InputList.push_back(Key(K::Point_2(3,2.1), 'c'));
Range_tree_2->make_tree(InputList.begin(),InputList.end());
Interval win(Interval(K::Point_2(1,2.1),K::Point_2(8.1,8.2)));
std::cout << "\n Window Query:\n";
Range_tree_2->window_query(win, std::back_inserter(OutputList));
std::vector<Key>::iterator current=OutputList.begin();
while(current!=OutputList.end()){
std::cout << " " << (*current).first.x() << "," << (*current).first.y()
<< ":" << (*current).second << std::endl;
current++;
}
std::cout << "\n Done\n";
}
void initcreate_tree() {;}
using namespace boost::python;
BOOST_PYTHON_MODULE(test)
{
def("create_tree", create_tree, "");
}
// setup.py
#!/usr/bin/env python
from distutils.core import setup
from distutils.extension import Extension
setup(name="PackageName",
ext_modules=[
Extension("test", ["test.cpp"],
libraries = ["boost_python"])
])
然后我们编译并运行该模块,如下所示
$ python setup.py build $ cd build/lib* $ python >>> import test >>> test.create_tree() Window Query: 3,2.1:c 8,5.1:a Done >>>
还可以处理更复杂的数据,例如 Python 对象,如列表。使用对对象“attr”函数输出执行的提取函数访问属性。我们也可以通过告诉库发生了错误并返回来抛出错误。在以下情况下,我们编写了一个名为“afunction”的 C++ 函数,我们希望调用它。该函数以整数 N 和长度为 N 的向量作为输入,我们必须在调用该函数之前将 Python 列表转换为字符串向量。
#include <vector>
using namespace std;
void _afunction_wrapper(int N, boost::python::list mapping) {
int mapping_length = boost::python::extract<int>(mapping.attr("__len__")());
//Do Error checking, the mapping needs to be at least as long as N
if (mapping_length < N) {
PyErr_SetString(PyExc_ValueError,
"The string mapping must be at least of length N");
boost::python::throw_error_already_set();
return;
}
vector<string> mystrings(mapping_length);
for (int i=0; i<mapping_length; i++) {
mystrings[i] = boost::python::extract<char const *>(mapping[i]);
}
//now call our C++ function
_afunction(N, mystrings);
}
using namespace boost::python;
BOOST_PYTHON_MODULE(c_afunction)
{
def("afunction", _afunction_wrapper);
}
- Boost.Python,boost.org
- pybind11,pypi.org