用一些简单的例子来记录下常见用法。

导出模块

导出一个空的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_readonlydef_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_multipletry_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

参考