利用Boost.Python实现Python C/C++混合编程

学习中如果碰到问题,参考官网例子:

D:\boost_1_61_0\libs\python\test

参考:Boost.Python 中英文文档。

利用Boost.Python实现Python C/C++混合编程

导出函数

#include
#include

using namespace std;
using namespace boost::python;


char const * greet()
{
    return "hello,world";

}

BOOST_PYTHON_MODULE(hello_ext)
{
    def("greet", greet);
}

python:

import hello_ext
print hello_ext.greet()

导出类:

导出默认构造的函数的类

c++

#include
#include

using namespace std;
using namespace boost::python;

struct World
{
    void set(string msg) { this->msg = msg; }
    string greet() { return msg; }

    string msg;
};

BOOST_PYTHON_MODULE(hello) //导出的module 名字
{
    class_("World")
        .def("greet", &World::greet)
        .def("set", &World::set);
}

python:

import hello 
planet = hello.World() # 调用默认构造函数,产生类对象
planet.set("howdy")   # 调用对象的方法
print planet.greet() # 调用对象的方法

构造函数的导出:

#include
#include

using namespace std;
using namespace boost::python;

struct World
{
    World(string msg):msg(msg){} //增加构造函数
    World(double a, double b):a(a),b(b) {} //另外一个构造函数
    void set(string msg) { this->msg = msg; }
    string greet() { return msg; }
    double sum_s() { return a + b; }
    string msg;
    double a;
    double b;
};

BOOST_PYTHON_MODULE(hello) //导出的module 名字
{
    class_("World",init<string>()) 
        .def(init<double,double>()) // expose another construct
        .def("greet", &World::greet)
        .def("set", &World::set)
        .def("sum_s", &World::sum_s);
}

python 测试调用:

import hello
planet = hello.World(5,6)
planet2 = hello.World("hollo world")

print planet.sum_s()
print planet2.greet()

如果不想导出任何构造函数,则使用no_init:

class_<Abstract>("Abstract",no_init)

类的数据成员

#include
#include

using namespace std;
using namespace boost::python;


struct Var
{
    Var(string name):name(name),value(){}
    string const name;

    float value;
};

BOOST_PYTHON_MODULE(hello_var)
{
    class_("Var", init<string>())
        .def_readonly("name", &Var::name) //只读
        .def_readwrite("value", &Var::value); //读写
}

python调用:

import hello_var

var = hello_var.Var("hello_var")
var.value = 3.14
# var.name = 'hello' # error
print var.name

C++类对象导出为Python的类对象,注意var.name不能赋值。

类的属性

// 类的属性

#include
#include

using namespace std;
using namespace boost::python;


struct Num
{
    Num(){}
    float get() const { return val; }
    void set(float val) { this->val = val; }
    float val;

};

BOOST_PYTHON_MODULE(hello_num)
{
    class_("Num")
        .add_property("rovalue", &Num::get) // 对外:只读
        .add_property("value", &Num::get, &Num::set);// 对外读写 .value值会改变.rovalue值,存储着同样的数据。

}

python:

import hello_num
num = hello_num.Num()
num.value = 10
print num.rovalue #  result: 10

继承

// 类的继承

#include
#include
#include

using namespace std;
using namespace boost::python;

struct Base {
    virtual ~Base() {};
    virtual string getName() { return "Base"; }

    string str;
};

struct Derived : Base {

    string getName() { return "Derived"; }

};


void b(Base *base) { cout << base->getName() << endl; };

void d(Derived *derived) { cout << derived->getName() << endl; };

Base * factory() { return new Derived; }

/*
    下面的额外的代码如果去掉会报错。
    解决地址:http://stackoverflow.com/questions/38261530/unresolved-external-symbols-since-visual-studio-2015-update-3-boost-python-link/38291152#38291152
*/
namespace boost
{
    template <>
    Base const volatile * get_pointer<class Base const volatile >(
        class Base const volatile *c)
    {
        return c;
    }
}


BOOST_PYTHON_MODULE(hello_derived)
{
    class_("Base")
        .def("getName", &Base::getName)
        .def_readwrite("str", &Base::str);


    class_ >("Derived")
        .def("getName", &Derived::getName)
        .def_readwrite("str", &Derived::str);


    def("b", b);
    def("d", d);

    def("factory", factory,
        return_value_policy());//

}

python:

import hello_derived
derive = hello_derived.factory()
hello_derived.d(derive)

类的虚函数:



/*
 类的虚函数,实现的功能是:可以编写Python类,来继承C++类
*/
#include

#include
#include
#include

using namespace boost::python;
using namespace std;

struct Base
{
    virtual ~Base() {}
    virtual int f() { return 0; };
};


struct BaseWrap : Base, wrapper
{
    int f()
    {
        if (override f = this->get_override("f"))
            return f(); //如果函数进行重载了,则返回重载的
        return Base::f(); //否则返回基类
    }
    int default_f() { return this->Base::f(); }
};

BOOST_PYTHON_MODULE(hello_virtual)
{
    class_("Base")
        .def("f", &Base::f, &BaseWrap::default_f);


}

python:

import hello_virtual 


base = hello_virtual.Base()
# 定义派生类,继承C++类
class Derived(hello_virtual.Base):
    def f(self):
        return 42

derived = Derived()


print base.f()

print derived.f()

类的运算符/特殊函数

// 类的运算符/特殊函数

#include
#include


// #include 如果仅包含该头文件,会出错

#include 
#include 
#include 
#include 
#include 

using namespace std;
using namespace boost::python;

class FilePos
{
public:
    FilePos() :len(0) {}
    operator double()const { return len; };//重载类型转换符
    int len;
};

// operator 方法

FilePos operator+(FilePos pos, int a)
{
    pos.len = pos.len + a;

    return pos; //返回的是副本

}

FilePos operator+(int a, FilePos pos)
{
    pos.len = pos.len + a;

    return pos; //返回的是副本

}


int operator-(FilePos pos1, FilePos pos2)
{

    return (pos1.len - pos2.len);

}

FilePos operator-(FilePos pos, int a)
{
    pos.len = pos.len - a;
    return pos;
}

FilePos &operator+=(FilePos & pos, int a)
{
    pos.len = pos.len + a;
    return pos;
}

FilePos &operator-=(FilePos & pos, int a)
{
    pos.len = pos.len - a;
    return pos;
}

bool operator<(FilePos  pos1, FilePos pos2)
{
    if (pos1.len < pos2.len)
        return true;
    return false;
}


//特殊的方法

FilePos pow(FilePos pos1, FilePos pos2)
{
    FilePos res;
    res.len = std::pow(pos1.len, pos2.len);
    return res;

}
FilePos abs(FilePos pos)
{
    FilePos res;
    res.len = std::abs(pos.len);

    return res;
}

ostream& operator<<(ostream& out, FilePos pos)
{
    out << pos.len;
    return out;
}

BOOST_PYTHON_MODULE(hello_operator)
{
    class_("FilePos")
        .def_readwrite("len",&FilePos::len)
        .def(self + int())
        .def(int() + self)
        .def(self - self)
        .def(self - int())
        .def(self += int())
        .def(self -= other<int>())
        .def(self < self)
        .def(float_(self))//特殊方法 ,     __float__
        .def(pow(self, other()))  // __pow__
        .def(abs(self))         //  __abs__
        .def(str(self));                //  __str__ for ostream


}

注意上面的:.def(pow(self, other()))模板后面要加上括号。也要注意头文件的包含,否则会引发错误。

python:

import hello_operator

filepos1 = hello_operator.FilePos()
filepos1.len = 10

filepos2 = hello_operator.FilePos()
filepos2.len = 20;

print filepos1 - filepos2

函数

函数的调用策略。


// 函数的调用策略 

#include
#include

#include

using namespace std;
using namespace boost::python;

struct X
{
    string str;
};
struct Z
{
    int value;
};

struct Y
{
    X x;
    Z *z;
    int z_value() { return z->value; }
};

X & f(Y &y, Z*z)
{
    y.z = z;
    return y.x;  //因为x是y的数据成员,x的声明周期与y进行了绑定。因为我们的目的是:Python接口应尽可能的反映C++接口
}


BOOST_PYTHON_MODULE(hello_call_policy)
{

    class_("Y")
        .def_readwrite("x", &Y::x)
        .def_readwrite("z", &Y::z)
        .def("z_value", &Y::z_value);
    class_("X")
        .def_readwrite("str", &X::str);
    class_("Z")
        .def_readwrite("value", &Z::value);
    // return_internal_reference<1 表示返回的值与第一个参数有关系:即第一个参数是返回对象的拥有者(y和x都是引用的形式)。
    // with_custodian_and_ward<1, 2> 表示第二个参数的生命周期依赖于第一个参数的生命周期。
    def("f", f, return_internal_reference<1, with_custodian_and_ward<1, 2> >());
}

函数重载

// overloading

#include
#include

#include

using namespace std;
using namespace boost::python;

struct X
{

    bool f(int a)
    {
        return true;
    }
    bool f(int a, double b)
    {
        return true;
    }
    bool f(int a, double b, char c)
    {
        return true;
    }
    int f(int a, int b, int c)
    {
        return a + b + c;
    }
};
bool (X::*fx1)(int) = &X::f;
bool(X::*fx2)(int, double) = &X::f;
bool(X::*fx3)(int, double,char) = &X::f;
int(X::*fx4)(int, int,int) = &X::f;

BOOST_PYTHON_MODULE(hello_overloaded)
{
    class_("X")
        .def("f", fx1)
        .def("f", fx2)
        .def("f", fx3)
        .def("f", fx4);

}

python:

import hello_overloaded

x = hello_overloaded.X() # create a new object


print x.f(1)  # default int type
print x.f(2,double(3))
print x.f(4,double(5),chr(6))  # chr(6) convert * to char 
print x.f(7,8,9)

默认参数

普通函数的默认参数:

然而通过上面的方式对重载函数进行封装时,就丢失了默认参数的信息。当然我们可以通过一般形式的封装,如下:

int f(int,double = 3.14,char const * = "hello");
int f1(int x){ return f(x);}
int f2(int x,double y){return f(x,y)}

//int module init
def("f",f); // 所有参数
def("f",f2); //两个参数
def("f",f1); //一个参数

但是通过上面的形式封装很麻烦。我们可以通过宏的形式,为我们批量完成上面的功能。

C++:


// BOOST_PYTHON_FUNCTION_OVERLOADS

#include
#include

#include


using namespace std;
using namespace boost::python;


void foo(int a, char b = 1, unsigned c = 2, double d = 3)
{
    return;
}

BOOST_PYTHON_FUNCTION_OVERLOADS(foo_overloads, foo, 1, 4); // 参数个数的最小为1,最大为4

BOOST_PYTHON_MODULE(hello_overloaded)
{

    def("foo", foo, foo_overloads()); //实现导出带有默认参数的函数

}

python:

import hello_overloaded


hello_overloaded.foo(1)

hello_overloaded.foo(1,chr(2))

hello_overloaded.foo(1,chr(2),3)  # 3对应的C++为unsigned int

hello_overloaded.foo(1,chr(2),3,double(4))

成员函数的默认参数:


//使用BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS 宏,完成成员函数默认参数的接口

#include
#include

#include


using namespace std;
using namespace boost::python;

struct george
{
    void wack_em(int a, int b = 0, char c = 'x')
    {
        return;
    }

};


BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS(george_overloads, wack_em, 1, 3); // 参数个数的最小为1,最大为3

BOOST_PYTHON_MODULE(hello_member_overloaded)
{

    class_("george")
        .def("wack_em", &george::wack_em, george_overloads());

}

python:

import hello_member_overloaded

c = hello_member_overloaded.george()

c.wack_em(1)
c.wack_em(1,2)
c.wack_em(1,2,chr(3))

利用init和optional实现构造函数的重载。
使用方法如下:


// init  optional

#include
#include
#include

using namespace std;
using namespace boost::python;

struct X
{
    X(int a, char b = 'D', string c = "constructor", double b = 0.0) {}
};

BOOST_PYTHON_MODULE(hello_construct_overloaded)
{
    class_("X")
        .def(init<int, optional<char, string, double> >()); // init 和 optional

}

对象接口

Python 是动态类型的语言,C++是静态类型的。Python变量可能是:integer,float ,list ,dict,tuple,str,long,等等,还有其他类型。从Boost.Python和C++的观点来看,Python中的变量是类object的实例,在本节,我们看一下如何处理Python对象。

基本接口


// init  optional

#include
#include
#include
#include 
using namespace std;
using namespace boost::python;

namespace bp = boost::python;


void f(object x)
{
    int y = extract<int>(x); // retrieve an int from x

}

int g(object x)
{
    extract<int> get_int(x);
    if (get_int.check())
        return get_int();
    else
        return 0;
}


int test(object &x)
{
    dict d = extract(x.attr("__dict__"));
    d["whatever"] = 4;
    return 0;
}

int test2(dict & d)
{
    d["helloworld"] = 3;
    return 0;
}
class A {

public:
    list lst;
    void listOperation(list &lst) {};
};

// 传入np.array数组对象,让C++进行处理
int add_arr_1(object & data_obj, object rows_obj, object cols_obj)
{
    PyArrayObject* data_arr = reinterpret_cast(data_obj.ptr());
    float * data = static_cast<float *>(PyArray_DATA(data_arr));
    // using data
    int rows = extract<int>(rows_obj);
    int cols = extract<int>(cols_obj);
    for (int i = 0; i < rows*cols; i++)
    {
        data[i] += 1;
    }
    return 0;

}
BOOST_PYTHON_MODULE(hello_object)
{
    def("test", test);
    def("test2", test2);
    def("add_arr_1", add_arr_1);
}

python 调用:

import hello_object

dic1 = {"whatever":1}

hello_object.test2(dic1)

arr = np.array([1,2,3],dtype = float32)

print arr.dtype

print arr

hello_object.add_arr_1(arr,1,3)

print arr

你可能感兴趣的:(Python/C,C++混合编程)