Use some simple examples to note common usage.

Export module

Export an empty Python module,

BOOST_PYTHON_MODULE(py_sample) {
}
Copy the code

You can dir the contents of the exported module in the corresponding Python code,

import py_sample
print dir(py_sample)  # ['__doc__', '__name__', '__package__']
Copy the code

The export function

Define functions in C++ and export them accordingly,

std::string Foobar() {
        return "foobar";
}

BOOST_PYTHON_MODULE(py_sample) {
    def("foobar", Foobar);
}
Copy the code

For function arguments and return value is a simple type, such as int/long/float/double/Boolean, string, etc., the Boost will automatically be transformed.

Derived classes

To get straight to a specific example,

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)
            ;
}
Copy the code

Constructor derivation

For constructors, if only one constructor exists, the class name is followed by the init block. If multiple constructors exist, the rest of the constructors begin with.def(init<… >()) to export.

Member function export

For functions, export via def operation.

Member variable export

For public fields, you can export them by def_readonly or def_readwrite. For private fields, you need to export them by add_property and provide corresponding getter/setter interfaces.

Inheritance relationship treatment

C++ class Base* (Base*); 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);
}
Copy the code

The above export loses inheritance in Python and cannot pass the Child instance to the Process function,

from py_sample import Base, Child, process
instance = Child("child")
print isinstance(instance, Child), isinstance(instance, Base)   # True, False
Copy the code

The call,

process(instance);
Copy the code

The following exception occurs,

Boost.Python.ArgumentError: Python argument types in
    py_sample.process(Child)
did not match C++ signature:
    process(class Base *)
Copy the code

In order to handle the inheritance relationship of the exported class, you need to display the base class when exporting the class.

class_<Child, bases<Base>>("Child", init<std::string>())
        ;
Copy the code

The isinstance judgment above returns the expected result and process can be called normally.

Inherit exported classes in Python

If you define a pure virtual or virtual function in a C++ class and want to inherit the class from Python and override the corresponding function, you need to use 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) ; }Copy the code

Make the following call in 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
Copy the code

The try_multiple and try_get_value interfaces defined above are intended to show that by defining them in this way, you can obtain in C++ code the effects of overloading defined in Python.

Function default argument processing

Normal function default argument processing,

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());
}
Copy the code

It is wrapped by BOOST_PYTHON_FUNCTION_OVERLOADS, with the 1,2 digits representing the minimum and maximum parameters respectively. Member functions defined on the class are modified with 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()) ; }Copy the code

Overload processing

Multiple overload functions can be defined in C++. When exporting, for the overload function with a common prefix parameter, BOOST_PYTHON_FUNCTION_OVERLOADS, BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS to help with the export,

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()) ; }Copy the code

Export the enumeration

Enumerations are much easier to export,

enum Enum {
        FIRST = 0,
        SECOND
};

BOOST_PYTHON_MODULE(py_sample) {
    enum_<Enum>("Enum")
        .value("FIRST", FIRST)
        .value("SECOND", SECOND)
        ;
}
Copy the code

Used in Python,

from py_sample import Enum
print Enum.FIRST, Enum.SECOND
Copy the code

reference

  • Boost Python Tutorial
  • Boost Python Wiki