#include
static PyObject *
spam_system(PyObject *self, PyObject *args)
{
const char *command;
int sts;
if (!PyArg_ParseTuple(args, "s", &command))
return NULL;
sts = system(command);
return Py_BuildValue("i", sts);
}
我们根据具体的操作系统和开发工具,把以上函数封装到一个动态链接库中,放入Python的动态链接库搜索路径(Python For Windows中是DLLs)中。就可以把它作为Python的一个模块使用。
Following C/C++ tradition, let's start with the "hello, world". A C++ Function:
char const* greet()
{
return "hello, world";
}
can be exposed to Python by writing a Boost.Python wrapper:
#include <boost/python.hpp>
using namespace boost::python;
BOOST_PYTHON_MODULE(hello)
{
def("greet", greet);
}
That's it. We're done. We can now build this as a shared library. The resulting DLL is now visible to Python. Here's a sample Python session:
>>> import hello
>>> print hello.greet()
hello, world
struct World的C++代码可以通过如下方式封装:
{
void set(std::string msg) { this->msg = msg; }
std::string greet() { return msg; }
std::string msg;
};
#include <boost/python.hpp>这里的关键点在于封装代码必有的 BOOST_PYTHON_MODULE 宏和class<>模板的def。为了支持C++类定义丰富的内容,Boost.Python提供了很多调用方法,比较常用,也比较重要的是构造函数、重载和虚函数的支持。
using namespace boost::python;
BOOST_PYTHON_MODULE(hello)
{
class_<World>("World")
.def("greet", &World::greet)
.def("set", &World::set)
;
}
class_<World>("World", init<std::string>())普通函数重载的支持事实上是一种函数封装方法,和这个函数是否是某个类的成员并无关系。基本思路是把不同的函数形式定义为不同的函数指针,然后以普通函数的形式封装。
.def(init<double, double>())
.def("greet", &World::greet)
.def("set", &World::set)
;
struct BaseWrap : Base, wrapper<Base>注意封装代码中class_的模板参数是BaseWrap,但def中的第二个函数是&Base::f。def的第三个函数提供函数封装的一些信息,这里指明了该虚函数的默认实现。更多的用法请参考Boost文档。在BOOST中还提供了更复杂的功能,比如可以定义Python类的属性(者甚至比在Python中更简单)。
{
int f()
{
if (override f = this->get_override("f"))
return f(); // *note*
return Base::f();
}
int default_f() { return this->Base::f(); }
};
class_<BaseWrap, boost::noncopyable>("Base")
.def("f", &Base::f, &BaseWrap::default_f)
;
#includePy_Initialize();启动虚拟机,Py_Finalize();终止它。PyRun_SimpleString用于执行语句。Boost延续了这一方式,并着眼于将交互过程变得更简单些。BOOST程序中最简单的示例如下:
int
main(int argc, char *argv[])
{
Py_Initialize();
PyRun_SimpleString("from time import time,ctime/n"
"print 'Today is',ctime(time())/n");
Py_Finalize();
return 0;
}
Py_Initialize();从这种复杂度的程序中,体现不出BOOST的优势,它甚至比C程序更复杂。不过这里可以学习一下它的基本框架。也许下面这个更为复杂的示例可以说明些问题:
object main_module((
handle<>(borrowed(PyImport_AddModule("__main__")))));
object main_namespace = main_module.attr("__dict__");
handle<> ignored((PyRun_String(
"hello = file('hello.txt', 'w')/n"
"hello.write('Hello world!')/n"
"hello.close()"
, Py_file_input
, main_namespace.ptr()
, main_namespace.ptr())
));
Py_Finalize();
object main_module((我们可以通过这里看到BOOST的一些优势,如通过 C++对象(这里main_namespace对象)获取Python数据,并将其转化为C++数据(extract模板)。而下面这个示例演示了BOOST为Python环境提供的C++异常保护:
handle<>(borrowed(PyImport_AddModule("__main__")))));
object main_namespace = main_module.attr("__dict__");
handle<> ignored((PyRun_String(
"result = 5 ** 2"
, Py_file_input
, main_namespace.ptr()
, main_namespace.ptr())
));
int five_squared = extract<int>(main_namespace["result"]);
try当然,我们也可以选择无异常的版本:
{
object result((handle<>(PyRun_String(
"5/0"
, Py_eval_input
, main_namespace.ptr()
, main_namespace.ptr()))
));
// execution will never get here:
int five_divided_by_zero = extract<int>(result);
}
catch(error_already_set)
{
// handle the exception in some way
}
handle<> result((allow_null(PyRun_String(
"5/0"
, Py_eval_input
, main_namespace.ptr()
, main_namespace.ptr()))));
if (!result)
// Python exception occurred
else
// everything went okay, it's safe to use the result
PyRunString是Python的C-API,Python提供了一系列的调用方法供程序执行脚本使用,也包括了PyRun_File这样的直接调用文件的功能,当然,它不支持C++的I/O,使用的是C风格的文件指针。
最后提一下,使用Boost,无论你是要扩展还是嵌入Python,都需要预编译Boost库,编译方法在Boost的文档中也有介绍。使用Boost的时候,要把预编译好的lib链接到link序列中,还要把DLL放到应用程序可以访问到的地方。
最后提一下,使用Boost,无论你是要扩展还是嵌入Python,都需要预编译Boost库,编译方法在Boost的文档中也有介绍。使用Boost的时候,要把预编译好的lib链接到link序列中,还要把DLL放到应用程序可以访问到的地方。