用一些简单的例子来记录下常见用法。
导出模块
导出一个空的Python模块,
BOOST_PYTHON_MODULE(py_sample) {
}
在相应的Python代码中可以dir查看导出模块的内容,
import py_sample
print dir(py_sample) # ['__doc__', '__name__', '__package__']
导出函数
在C++中定义函数,并做相应导出,
std::string Foobar() {
return "foobar";
}
BOOST_PYTHON_MODULE(py_sample) {
def("foobar", Foobar);
}
对于函数参数以及返回值是简单类型,比如int/long/float/double/bool/string
等,Boost会自动进行转化。
导出类
直接来看具体的例子,
class Base {
public:
Base(std::string name):
name_(name),
value1_(0),
value2_(0) {
}
Base(int value1, int value2): name_("") {
value1_ = value1;
value2_ = value2;
}
std::string GetName() {
return name_;
}
int getValue2() {
return value2_;
}
public:
std::string name_;
int value1_;
private:
int value2_;
};
BOOST_PYTHON_MODULE(py_sample) {
class_<Base>("Base", init<std::string>())
.def(init<int, int>())
.def("get_name", &Base::GetName)
.def_readonly("value1", &Base::value1_)
.add_property("value2", &Base::getValue2)
;
}
构造函数导出
对于构造函数,如果只存在一个构造函数,则直接在类名后跟上init
块,如果存在多个构造函数,则其余构造函数以.def(init<...>())
进行导出。
成员函数导出
对于函数来说,通过def
操作进行导出。
成员变量导出
对于类属性来说,如果是public
的字段,可以通过def_readonly
或def_readwrite
进行导出,对于private
字段,则需要通过add_property
来导出,提供对应的getter/setter
接口。
继承关系处理
考虑C++中的继承关系,实现一个Child
类继承Base
并直接导出,同时再定义导出一个处理基类指针Base*
的函数,
class Child: public Base {
public:
Child(std::string name):
Base(name) {
}
};
void Process(Base* base) {
}
BOOST_PYTHON_MODULE(py_sample) {
...
class_<Child>("Child", init<std::string>())
;
def("process", &Process);
}
上面的导出方式在Python中会丢失继承关系,并且无法将Child实例传递给Process函数,
from py_sample import Base, Child, process
instance = Child("child")
print isinstance(instance, Child), isinstance(instance, Base) # True, False
调用,
process(instance);
则会出现如下异常,
Boost.Python.ArgumentError: Python argument types in
py_sample.process(Child)
did not match C++ signature:
process(class Base *)
为了处理导出类的继承关系,需要在导出类的时候显示注明其基类,
class_<Child, bases<Base>>("Child", init<std::string>())
;
如此上述的isinstance
判断会返回预期结果,process
也能正常调用。
在Python中继承导出类
如果在C++类中定义了纯虚函数或虚函数,希望在Python中继承类并重载对应的函数,则需要通过wrapper
进行一定处理,
class Base {
public:
Base(): value_(0) {
}
virtual int GetValue() = 0;
virtual int Multiple(int v) {
return value_ * v;
}
int TryGetValue() {
return GetValue();
}
int TryMultiple(int v) {
return Multiple(v);
}
private:
int value_;
};
class BaseWrap: public Base, public wrapper<Base> {
public:
int GetValue() {
return this->get_override("get_value")();
}
int Multiple(int v) {
if (override f = this->get_override("multiple")) {
return f(v);
}
return Base::Multiple(v);
}
int DefaultMultiple(int v) {
return this->Base::Multiple(v);
}
};
BOOST_PYTHON_MODULE(py_sample) {
class_<BaseWrap, boost::noncopyable>("Base")
.def("try_multiple", &Base::TryMultiple)
.def("try_get_value", &Base::TryGetValue)
.def("get_value", pure_virtual(&Base::GetValue))
.def("multiple", &Base::Multiple, &BaseWrap::DefaultMultiple)
;
}
在Python中进行如下调用,
from py_sample import Base
class Child(Base):
def multiple(self, v):
return 1000
def get_value(self):
return 1000
child = Child()
base = Base()
print child.try_multiple(1) # 1000
print base.try_multiple() # 0
print child.try_get_value() # 1000
print base.try_get_value() # exception
上面定义的try_multiple
、try_get_value
两个接口是为了说明以这种方式定义,可以在C++代码中获得Python中定义的重载效果。
函数默认参数处理
普通函数的默认参数处理,
int Foo(int a, int b=1) {
return a * b;
}
BOOST_PYTHON_FUNCTION_OVERLOADS(FooOverloads, Foo, 1, 2)
BOOST_PYTHON_MODULE(py_sample) {
def("foo", Foo, FooOverloads());
}
通过BOOST_PYTHON_FUNCTION_OVERLOADS
进行包装,上面的1,2数字分别代表最少参数个数与最大参数个数。定义在类上的成员函数则通过BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS
进行修饰,
class Base {
public:
int Foo(int a, int b=1) {
return a * b;
}
};
BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS(FooOverloads, Base::Foo, 1, 2)
BOOST_PYTHON_MODULE(py_sample) {
class_<Base>("Base")
.def("foo", &Base::Foo, FooOverloads())
;
}
函数overload处理
C++中可以定义多个overload函数,在导出的时候,对于有公共前缀参数的overload函数来说,可以通过BOOST_PYTHON_FUNCTION_OVERLOADS
, BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS
来帮助进行导出,
class Base {
public:
int Foo(int a, int b) {
return a * b;
}
int Foo(int a, int b, int c) {
return a * b * c;
}
};
BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS(FooOverloads, Base::Foo, 2, 3)
BOOST_PYTHON_MODULE(py_sample) {
class_<Base>("Base")
.def("foo", (int(Base::*)(int, int, int)) 0, FooOverloads())
;
}
导出枚举
枚举的导出简单很多,
enum Enum {
FIRST = 0,
SECOND
};
BOOST_PYTHON_MODULE(py_sample) {
enum_<Enum>("Enum")
.value("FIRST", FIRST)
.value("SECOND", SECOND)
;
}
在Python中使用,
from py_sample import Enum
print Enum.FIRST, Enum.SECOND