Boost.Python实现C++与Python互调用
2010-06-21 22:49
639 查看
Technorati 标签: C++
,Python
,Boost
【编者按】最近一直发Python的资料,是因为Python的脚本扩展性。现在.net的动态语言特性已经很强大了,似乎脚本的作用并不明显。但是对于老式的C++,如果能够结合脚本语言的动态性,引用最近流行的一句话:必可以形成犄角之势!C++调用Python可以通过API,也可以通过Boost库实现,Boost.Python就是对API的包装,方便调用而已。
这是一篇比较老的介绍Boost.Python的文章,权当入门吧。因为文中一些东西现在不对……
Boost.Python
是 Boost
中的一个组件, 使用它能够大大简化用 C++ 为 Python 写扩展库的步骤, 提高开发效率, 虽然目前它对 Python 嵌入 C++ 的支持还不是很多, 但也能提供很大方便。 另外, 华宇煜
也编写了一份关于 Boost.Python 简明教程
。
1 Boost 安装简介
在正式开始使用 Boost.Python 之前, 我们必须先编译 Boost。 首先到 Boost 的官方站点
下载 Boost 的源码包, 把它们解压到你喜欢的目录, 为编译做好准备。 另外, 在正式安装 Boost.Python 之前, 我们必须先正确安装 Python。
1.1 Linux 下的编译
首先切换到 Boost 源码所在的路径, 执行
脚本, 为配置脚本提供 Python 运行环境相应的参数:
./configure --with-python=/usr/bin/python /
--with-python-version=2.4 /
--with-python-root=/usr
然后, 和绝大部分 Linux 程序一行, 执行
就可以开始编译了。 编译完毕后, 切换到 root 权限后再执行
, 把 Boost 相应的头文件和库文件复制到相应的地方, 就可以使用了。
1.2 使用 MinGW + MSys 在 Windows 下的编译
首先需要编译的是 Boost 的编译工具 bjam, 直接到 bjam 所在目录下, 即 Boost 源码包所在目录下的
, 执行
, 稍等片刻, bjam.exe 就编译好了。 把编译好的 bjam.exe 复制到你的
路径能够直接找到的地方, 为后续的编译工作做好准备。
接下来, 切换到 Boost 源码所在路径, 执行 bjam 进行编译。 我们需要提供关于 Python 的一些参数, 变量 PYTHON_ROOT 指向 Python 运行环境所在的目录, 变量 PYTHON_VERSION 的值为 Python 的版本号, 如果你的 Python 安装路径与滇狐不同, 请将相应的变量修改为你机器上相应的路径, 编译命令行如下:
bjam.exe "-sTOOLS=mingw" "-sPYTHON_ROOT=E:/Python" "-sPYTHON_VERSION=2.4"
编译完毕后, 你将会在你的
下找到编译得到的 Boost 相应头文件与库文件, 你可以根据你的需要将它移动到别的地方备用。
2 使用 Boost.Python 嵌入 Python 模块到 C++
Boost.Python 目前并没有提供完整的将 Python 模块嵌入到 C++ 的包装库, 因此许多工作我们还必须通过 Python C API 来进行。 但是, 利用 Boost.Python 中提供的一些模块, 能够给我们的工作带来极大便利。
2.1 修改模块加载路径,装入 Python 模块
与任何一个其它 Python 嵌入 C/C++ 的程序一样, 我们需要在第一条
语句处含入
, 并在程序开始时调用
, 在程序结束时调用
。
接下来, 我们便可以开始准备装入 Python 模块了。 为了让 Python 解释器能够正确地找到 Python 模块所在的位置, 我们需要将 Python 模块所在的路径添加到模块搜索路径中, 添加搜索路径的 Python 语句如下:
import
sys
if
not
'/module/path
' in
sys.path:
sys.path.append('/module/path
')
我们使用 Python C API 执行类似的语句, 就能将模块的搜索路径添加到 Python 解释器中。 添加了搜索路径后, 就可以通过
函数加载 Python 模块了。
返回值是
, 为了避免手工处理繁琐的引用计数等问题, 我们求助于 Boost.Python 提供的
模块, 将
封装起来, 以方便使用, 代码如下:
#include
...
boost::python::handle<>* _module; // Module handle.
std::string path; // Path of the Python module.
std::string module; // Module name.
...
try
{
PyRun_SimpleString("import sys"
);
PyRun_SimpleString((std::string("if not '"
) + path
+ "' in sys.path: sys.path.append('"
+ path + "')"
).c_str());
_module = new
boost::python::handle<>(
PyImport_ImportModule((char
*) module));
...
}
catch
(...)
{
PyErr_Print();
PyErr_Clear();
delete
_module;
_module = NULL
;
return
false
;
}
...
需要注意的是, 通过 Python C API 加载的 Python 解释器并没有把当前路径列入默认的搜索路径中。 因此, 即使你的 Python 模块就存放在当前路径, 你也必须使用上面的代码将当前路径添加到搜索路径中之后, 才能通过
加载到模块。
当 Python 模块使用完毕或程序结束时, 请使用
将
指针释放,
被释放的时候会自动释放相应的 Python 模块并回收相应资源。
2.2 调用 Python 函数
导入了 Python 模块之后, 调用 Python 函数就非常容易了。 Boost.Python 里封装了一个非常好用的模板函数
, 它可以替你处理调用函数时需要处理的种种细节, 将你从 Python C API 中繁琐的“将参数打包为
”、 “构造 Tuple”、 “传递 Tuple”、 “解包返回值”等工作中彻底解放出来, 你只需要这样:
boost::python::call_method<返回值类型>(模块指针, "Python 函数名"
,
参数 1
, 参数 2
, ...);
模块指针可以通过我们前面得到的
的
方法获得, 例如:
...
bool
result;
std::string config_file;
...
try
{
return
boost::python::call_method<bool
>(_module->get(), "initialize"
,
config_file);
}
catch
(...)
{
PyErr_Print();
PyErr_Clear();
...
}
...
2.3 使用 Python 类对象
使用 Python C API 调用 Python 函数和调用 Python 类对象是没有太大区别的, 我们只需要调用类的构造方法, 得到一个类对象, 然后把该类的指针看做模块指针, 按照前面调用普通函数的方法调用类成员方法就可以了。 例如, 下列代码从
中创建了一个
对象, 然后调用了其中的
方法。 除了展示调用类成员方法外, 这段代码还展示了构造 Python list 对象、 从 Python list 对象中获取元素的方式。
...
boost::python::handle<> _yukisession;
...
// Retrieve the module handle and namespace handle.
boost::python::object main_module(*_module);
boost::python::object main_namespace = main_module.attr("__dict__"
);
// Call the method and get the object handle.
_yukisession = boost::python::handle<>((PyRun_String(
"YukiSession()"
, Py_eval_input,
main_namespace.ptr(), main_namespace.ptr())));
...
// Compose a list.
boost::python::list param;
param.append(boost::python::str(_addr.get_host_addr()));
param.append(boost::python::str());
// Call the method and retrieve the result.
// Method is equivalent to:
// "bool __thiscall YukiSession::on_welcome(list param);"
result = boost::python::call_method<bool
>
(_yukisession.get(), "on_welcome"
, param);
// Extract an item from a list.
str = boost::python::call_method
(param.ptr(), "__getitem__"
, 1
);
...
3 在嵌入的 Python 模块中调用 C++ 程序
通过动态链接库的方式使用 Boost.Python 导出 C++ 模块到 Python 程序与在 C++ 可执行程序中导出模块给嵌入的 Python 解释器, 编写程序的方式几乎是完全相同的。 因此这里只简单介绍导出普通函数的方法, 想详细了解更多高级功能, 如导出 C++ 类、 导出可被 Python 重载的类等, 可以参看华宇煜的 Boost.Python 简明教程
或官方 Boost.Python
文档。
3.1 导出 C++ 函数
首先使用
宏定义需要导出给 Python 的模块, 然后用
语句定义导出的函数、 参数列表以及 Doc String, 例如在下面的例子中, 我们导出了一个 C++ 函数
, 并重命名为
:
const
char
*yukigettext(const
char
*id);
BOOST_PYTHON_MODULE(yuki)
{
boost::python::def("gettext"
, yukigettext,
boost::python::args("id"
), "Translate message."
);
}
3.2 为 Python 初始化 C++ 模块
使用
定义了 Python 模块后, 该宏会自动生成一个函数
, 我们需要在
之后调用这个自动生成的函数, 初始化导出到 Python 的模块。 例如我们刚才导出模块用的宏
, 因此初始化的时候就应该调用
:
...
Py_Initialize();
inityuki();
...
3.3 在 Python 模块中调用 C++ 模块
此时我们在 Python 模块中只需要像普通的 Python 模块那样, 将导入的 C++ 模块用
语句加载进来, 就可以调用了:
import
yuki
...
print
yuki.gettext("This is a test!
")
原文:http://edyfox.codecarver.org/html/boost_python.html
,Python
,Boost
【编者按】最近一直发Python的资料,是因为Python的脚本扩展性。现在.net的动态语言特性已经很强大了,似乎脚本的作用并不明显。但是对于老式的C++,如果能够结合脚本语言的动态性,引用最近流行的一句话:必可以形成犄角之势!C++调用Python可以通过API,也可以通过Boost库实现,Boost.Python就是对API的包装,方便调用而已。
这是一篇比较老的介绍Boost.Python的文章,权当入门吧。因为文中一些东西现在不对……
Boost.Python
是 Boost
中的一个组件, 使用它能够大大简化用 C++ 为 Python 写扩展库的步骤, 提高开发效率, 虽然目前它对 Python 嵌入 C++ 的支持还不是很多, 但也能提供很大方便。 另外, 华宇煜
也编写了一份关于 Boost.Python 简明教程
。
1 Boost 安装简介
在正式开始使用 Boost.Python 之前, 我们必须先编译 Boost。 首先到 Boost 的官方站点下载 Boost 的源码包, 把它们解压到你喜欢的目录, 为编译做好准备。 另外, 在正式安装 Boost.Python 之前, 我们必须先正确安装 Python。
1.1 Linux 下的编译
首先切换到 Boost 源码所在的路径, 执行 ./configure
脚本, 为配置脚本提供 Python 运行环境相应的参数:
./configure --with-python=/usr/bin/python /
--with-python-version=2.4 /
--with-python-root=/usr
然后, 和绝大部分 Linux 程序一行, 执行
make
就可以开始编译了。 编译完毕后, 切换到 root 权限后再执行
make install
, 把 Boost 相应的头文件和库文件复制到相应的地方, 就可以使用了。
1.2 使用 MinGW + MSys 在 Windows 下的编译
首先需要编译的是 Boost 的编译工具 bjam, 直接到 bjam 所在目录下, 即 Boost 源码包所在目录下的 /tools/build/jam_src
, 执行
build.bat mingw
, 稍等片刻, bjam.exe 就编译好了。 把编译好的 bjam.exe 复制到你的
%PATH%
路径能够直接找到的地方, 为后续的编译工作做好准备。
接下来, 切换到 Boost 源码所在路径, 执行 bjam 进行编译。 我们需要提供关于 Python 的一些参数, 变量 PYTHON_ROOT 指向 Python 运行环境所在的目录, 变量 PYTHON_VERSION 的值为 Python 的版本号, 如果你的 Python 安装路径与滇狐不同, 请将相应的变量修改为你机器上相应的路径, 编译命令行如下:
bjam.exe "-sTOOLS=mingw" "-sPYTHON_ROOT=E:/Python" "-sPYTHON_VERSION=2.4"
编译完毕后, 你将会在你的
C:/Boost
下找到编译得到的 Boost 相应头文件与库文件, 你可以根据你的需要将它移动到别的地方备用。
2 使用 Boost.Python 嵌入 Python 模块到 C++
Boost.Python 目前并没有提供完整的将 Python 模块嵌入到 C++ 的包装库, 因此许多工作我们还必须通过 Python C API 来进行。 但是, 利用 Boost.Python 中提供的一些模块, 能够给我们的工作带来极大便利。2.1 修改模块加载路径,装入 Python 模块
与任何一个其它 Python 嵌入 C/C++ 的程序一样, 我们需要在第一条 #include
语句处含入
Python.h
, 并在程序开始时调用
Py_Initialize()
, 在程序结束时调用
Py_Finalize()
。
接下来, 我们便可以开始准备装入 Python 模块了。 为了让 Python 解释器能够正确地找到 Python 模块所在的位置, 我们需要将 Python 模块所在的路径添加到模块搜索路径中, 添加搜索路径的 Python 语句如下:
import
sys
if
not
'/module/path
' in
sys.path:
sys.path.append('/module/path
')
我们使用 Python C API 执行类似的语句, 就能将模块的搜索路径添加到 Python 解释器中。 添加了搜索路径后, 就可以通过
PyImport_ImportModule
函数加载 Python 模块了。
PyImport_ImportModule
返回值是
PyObject *
, 为了避免手工处理繁琐的引用计数等问题, 我们求助于 Boost.Python 提供的
handle
模块, 将
PyObject *
封装起来, 以方便使用, 代码如下:
#include
...
boost::python::handle<>* _module; // Module handle.
std::string path; // Path of the Python module.
std::string module; // Module name.
...
try
{
PyRun_SimpleString("import sys"
);
PyRun_SimpleString((std::string("if not '"
) + path
+ "' in sys.path: sys.path.append('"
+ path + "')"
).c_str());
_module = new
boost::python::handle<>(
PyImport_ImportModule((char
*) module));
...
}
catch
(...)
{
PyErr_Print();
PyErr_Clear();
delete
_module;
_module = NULL
;
return
false
;
}
...
需要注意的是, 通过 Python C API 加载的 Python 解释器并没有把当前路径列入默认的搜索路径中。 因此, 即使你的 Python 模块就存放在当前路径, 你也必须使用上面的代码将当前路径添加到搜索路径中之后, 才能通过
PyImport_ImportModule
加载到模块。
当 Python 模块使用完毕或程序结束时, 请使用
delete
将
_module
指针释放,
handle
被释放的时候会自动释放相应的 Python 模块并回收相应资源。
2.2 调用 Python 函数
导入了 Python 模块之后, 调用 Python 函数就非常容易了。 Boost.Python 里封装了一个非常好用的模板函数 boost::python::call_method
, 它可以替你处理调用函数时需要处理的种种细节, 将你从 Python C API 中繁琐的“将参数打包为
PyObject *
”、 “构造 Tuple”、 “传递 Tuple”、 “解包返回值”等工作中彻底解放出来, 你只需要这样:
boost::python::call_method<返回值类型>(模块指针, "Python 函数名"
,
参数 1
, 参数 2
, ...);
模块指针可以通过我们前面得到的
_module
的
get
方法获得, 例如:
...
bool
result;
std::string config_file;
...
try
{
return
boost::python::call_method<bool
>(_module->get(), "initialize"
,
config_file);
}
catch
(...)
{
PyErr_Print();
PyErr_Clear();
...
}
...
2.3 使用 Python 类对象
使用 Python C API 调用 Python 函数和调用 Python 类对象是没有太大区别的, 我们只需要调用类的构造方法, 得到一个类对象, 然后把该类的指针看做模块指针, 按照前面调用普通函数的方法调用类成员方法就可以了。 例如, 下列代码从 _module
中创建了一个
YukiSession
对象, 然后调用了其中的
on_welcome
方法。 除了展示调用类成员方法外, 这段代码还展示了构造 Python list 对象、 从 Python list 对象中获取元素的方式。
...
boost::python::handle<> _yukisession;
...
// Retrieve the module handle and namespace handle.
boost::python::object main_module(*_module);
boost::python::object main_namespace = main_module.attr("__dict__"
);
// Call the method and get the object handle.
_yukisession = boost::python::handle<>((PyRun_String(
"YukiSession()"
, Py_eval_input,
main_namespace.ptr(), main_namespace.ptr())));
...
// Compose a list.
boost::python::list param;
param.append(boost::python::str(_addr.get_host_addr()));
param.append(boost::python::str());
// Call the method and retrieve the result.
// Method is equivalent to:
// "bool __thiscall YukiSession::on_welcome(list param);"
result = boost::python::call_method<bool
>
(_yukisession.get(), "on_welcome"
, param);
// Extract an item from a list.
str = boost::python::call_method
(param.ptr(), "__getitem__"
, 1
);
...
3 在嵌入的 Python 模块中调用 C++ 程序
通过动态链接库的方式使用 Boost.Python 导出 C++ 模块到 Python 程序与在 C++ 可执行程序中导出模块给嵌入的 Python 解释器, 编写程序的方式几乎是完全相同的。 因此这里只简单介绍导出普通函数的方法, 想详细了解更多高级功能, 如导出 C++ 类、 导出可被 Python 重载的类等, 可以参看华宇煜的 Boost.Python 简明教程或官方 Boost.Python
文档。
3.1 导出 C++ 函数
首先使用 BOOST_PYTHON_MODULE
宏定义需要导出给 Python 的模块, 然后用
boost::python::def
语句定义导出的函数、 参数列表以及 Doc String, 例如在下面的例子中, 我们导出了一个 C++ 函数
yukigettext
, 并重命名为
gettext
:
const
char
*yukigettext(const
char
*id);
BOOST_PYTHON_MODULE(yuki)
{
boost::python::def("gettext"
, yukigettext,
boost::python::args("id"
), "Translate message."
);
}
3.2 为 Python 初始化 C++ 模块
使用 BOOST_PYTHON_MODULE(name)
定义了 Python 模块后, 该宏会自动生成一个函数
initname
, 我们需要在
Py_Initialize()
之后调用这个自动生成的函数, 初始化导出到 Python 的模块。 例如我们刚才导出模块用的宏
BOOST_PYTHON_MODULE(yuki)
, 因此初始化的时候就应该调用
inityuki()
:
...
Py_Initialize();
inityuki();
...
3.3 在 Python 模块中调用 C++ 模块
此时我们在 Python 模块中只需要像普通的 Python 模块那样, 将导入的 C++ 模块用 import
语句加载进来, 就可以调用了:
import
yuki
...
yuki.gettext("This is a test!
")
原文:http://edyfox.codecarver.org/html/boost_python.html
相关文章推荐
- 使用boost实现python调用c++
- Boost.Python实现C++与Python互调用
- 使用boost实现c++与python的相互调用
- 如何在C++代码中调用python代码(MinGW+Boost.Python)
- CERL: PHP或Python调用C++实现的服务器
- python嵌入C++------ boost.python如何在C++中调用含有不定长参数tuple变量和关键字参数dict变量的函数
- 用boost封装C++的库供Python调用
- Python调用采用Boost Python封装的c++
- c++调用python实现
- Boost Python 实现C调用python错误解决方法
- [转]vs2010用 boost.python 编译c++类库 供python调用
- centos7下使用swig扩展python接口来调用c++ 实现声纹识别
- 利用Boost.Python实现Python C/C++混合编程
- Python调用采用Boost Python封装的c++(2)
- 利用swig实现python调用C/C++的方法
- c++调用Python [boost::python]
- centos中使用swig实现python调用c++
- 查看python调用c++代码的代码实现位于那个cpp文件
- Python调用C/C++的接口(Boost)
- 一个日历问题的C语言,C++(boost),python,Javascript,Java和Matlab的实现