您好,登錄后才能下訂單哦!
前言
學(xué)習(xí)中如果碰到問(wèn)題,參考官網(wǎng)例子:
D:\boost_1_61_0\libs\python\test
參考:Boost.Python 中英文文檔。
利用Boost.Python實(shí)現(xiàn)Python C/C++混合編程
關(guān)于python與C++混合編程,事實(shí)上有兩個(gè)部分
兩者都可以用 python c 轉(zhuǎn)換api,解決,具體可以去python官方文檔查閱,但是都比較繁瑣.
對(duì)于1,extending,常用的方案是boost.python以及swig.
swig是一種膠水語(yǔ)言,粘合C++,PYTHON,我前面的圖形顯示二叉樹(shù)的文章中提到的就是利用pyqt作界面,調(diào)用c++代碼使用swig生成的.so動(dòng)態(tài)庫(kù).
而boost.python則直接轉(zhuǎn)換,可以利用py++自動(dòng)生成需要的wrapper.關(guān)于這方面的內(nèi)容的入門除了boost.python官網(wǎng),中文的入門資料推薦
下面話不多說(shuō)了,來(lái)一起看看詳細(xì)的介紹吧
導(dǎo)出函數(shù)
#include<string> #include<boost/python.hpp> 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()
導(dǎo)出類:
導(dǎo)出默認(rèn)構(gòu)造的函數(shù)的類
c++
#include<string> #include<boost/python.hpp> 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) //導(dǎo)出的module 名字 { class_<World>("World") .def("greet", &World::greet) .def("set", &World::set); }
python:
import hello planet = hello.World() # 調(diào)用默認(rèn)構(gòu)造函數(shù),產(chǎn)生類對(duì)象 planet.set("howdy") # 調(diào)用對(duì)象的方法 print planet.greet() # 調(diào)用對(duì)象的方法
構(gòu)造函數(shù)的導(dǎo)出:
#include<string> #include<boost/python.hpp> using namespace std; using namespace boost::python; struct World { World(string msg):msg(msg){} //增加構(gòu)造函數(shù) World(double a, double b):a(a),b(b) {} //另外一個(gè)構(gòu)造函數(shù) 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) //導(dǎo)出的module 名字 { class_<World>("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 測(cè)試調(diào)用:
import hello planet = hello.World(5,6) planet2 = hello.World("hollo world") print planet.sum_s() print planet2.greet()
如果不想導(dǎo)出任何構(gòu)造函數(shù),則使用no_init:
class_<Abstract>("Abstract",no_init)
類的數(shù)據(jù)成員
#include<string> #include<boost/python.hpp> 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>("Var", init<string>()) .def_readonly("name", &Var::name) //只讀 .def_readwrite("value", &Var::value); //讀寫 }
python調(diào)用:
import hello_var var = hello_var.Var("hello_var") var.value = 3.14 # var.name = 'hello' # error print var.name
C++類對(duì)象導(dǎo)出為Python的類對(duì)象,注意var.name不能賦值。
類的屬性
// 類的屬性 #include<string> #include<boost/python.hpp> 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>("Num") .add_property("rovalue", &Num::get) // 對(duì)外:只讀 .add_property("value", &Num::get, &Num::set);// 對(duì)外讀寫 .value值會(huì)改變.rovalue值,存儲(chǔ)著同樣的數(shù)據(jù)。 }
python:
import hello_num num = hello_num.Num() num.value = 10 print num.rovalue # result: 10
繼承
// 類的繼承 #include<string> #include<iostream> #include<boost/python.hpp> 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; } /* 下面的額外的代碼如果去掉會(huì)報(bào)錯(cuò)。 解決地址: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>("Base") .def("getName", &Base::getName) .def_readwrite("str", &Base::str); class_<Derived, bases<Base> >("Derived") .def("getName", &Derived::getName) .def_readwrite("str", &Derived::str); def("b", b); def("d", d); def("factory", factory, return_value_policy<manage_new_object>());// }
python:
import hello_derived derive = hello_derived.factory() hello_derived.d(derive)
類的虛函數(shù):
/* 類的虛函數(shù),實(shí)現(xiàn)的功能是:可以編寫Python類,來(lái)繼承C++類 */ #include<boost/python.hpp> #include<boost/python/wrapper.hpp> #include<string> #include<iostream> using namespace boost::python; using namespace std; struct Base { virtual ~Base() {} virtual int f() { return 0; }; }; struct BaseWrap : Base, wrapper<Base> { int f() { if (override f = this->get_override("f")) return f(); //如果函數(shù)進(jìn)行重載了,則返回重載的 return Base::f(); //否則返回基類 } int default_f() { return this->Base::f(); } }; BOOST_PYTHON_MODULE(hello_virtual) { class_<BaseWrap, boost::noncopyable>("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()
類的運(yùn)算符/特殊函數(shù)
// 類的運(yùn)算符/特殊函數(shù) #include<string> #include<iostream> // #include<boost/python.hpp> 如果僅包含該頭文件,會(huì)出錯(cuò) #include <boost/python/operators.hpp> #include <boost/python/class.hpp> #include <boost/python/module.hpp> #include <boost/python/def.hpp> #include <boost/operators.hpp> using namespace std; using namespace boost::python; class FilePos { public: FilePos() :len(0) {} operator double()const { return len; };//重載類型轉(zhuǎn)換符 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>("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<FilePos>())) // __pow__ .def(abs(self)) // __abs__ .def(str(self)); // __str__ for ostream }
注意上面的:.def(pow(self, other<FilePos>()))模板后面要加上括號(hào)。也要注意頭文件的包含,否則會(huì)引發(fā)錯(cuò)誤。
python:
import hello_operator filepos1 = hello_operator.FilePos() filepos1.len = 10 filepos2 = hello_operator.FilePos() filepos2.len = 20; print filepos1 - filepos2
函數(shù)
函數(shù)的調(diào)用策略。
// 函數(shù)的調(diào)用策略 #include<string> #include<iostream> #include<boost/python.hpp> 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; //因?yàn)閤是y的數(shù)據(jù)成員,x的聲明周期與y進(jìn)行了綁定。因?yàn)槲覀兊哪康氖牵篜ython接口應(yīng)盡可能的反映C++接口 } BOOST_PYTHON_MODULE(hello_call_policy) { class_<Y>("Y") .def_readwrite("x", &Y::x) .def_readwrite("z", &Y::z) .def("z_value", &Y::z_value); class_<X>("X") .def_readwrite("str", &X::str); class_<Z>("Z") .def_readwrite("value", &Z::value); // return_internal_reference<1 表示返回的值與第一個(gè)參數(shù)有關(guān)系:即第一個(gè)參數(shù)是返回對(duì)象的擁有者(y和x都是引用的形式)。 // with_custodian_and_ward<1, 2> 表示第二個(gè)參數(shù)的生命周期依賴于第一個(gè)參數(shù)的生命周期。 def("f", f, return_internal_reference<1, with_custodian_and_ward<1, 2> >()); }
函數(shù)重載
// overloading #include<string> #include<iostream> #include<boost/python.hpp> 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>("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)
默認(rèn)參數(shù)
普通函數(shù)的默認(rèn)參數(shù):
然而通過(guò)上面的方式對(duì)重載函數(shù)進(jìn)行封裝時(shí),就丟失了默認(rèn)參數(shù)的信息。當(dāng)然我們可以通過(guò)一般形式的封裝,如下:
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); // 所有參數(shù) def("f",f2); //兩個(gè)參數(shù) def("f",f1); //一個(gè)參數(shù)
但是通過(guò)上面的形式封裝很麻煩。我們可以通過(guò)宏的形式,為我們批量完成上面的功能。
C++:
// BOOST_PYTHON_FUNCTION_OVERLOADS #include<string> #include<iostream> #include<boost/python.hpp> 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); // 參數(shù)個(gè)數(shù)的最小為1,最大為4 BOOST_PYTHON_MODULE(hello_overloaded) { def("foo", foo, foo_overloads()); //實(shí)現(xiàn)導(dǎo)出帶有默認(rèn)參數(shù)的函數(shù) } python: import hello_overloaded hello_overloaded.foo(1) hello_overloaded.foo(1,chr(2)) hello_overloaded.foo(1,chr(2),3) # 3對(duì)應(yīng)的C++為unsigned int hello_overloaded.foo(1,chr(2),3,double(4))
成員函數(shù)的默認(rèn)參數(shù):
//使用BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS 宏,完成成員函數(shù)默認(rèn)參數(shù)的接口 #include<string> #include<iostream> #include<boost/python.hpp> 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); // 參數(shù)個(gè)數(shù)的最小為1,最大為3 BOOST_PYTHON_MODULE(hello_member_overloaded) { class_<george>("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實(shí)現(xiàn)構(gòu)造函數(shù)的重載。
使用方法如下:
// init optional #include<string> #include<iostream> #include<boost/python.hpp> 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>("X") .def(init<int, optional<char, string, double> >()); // init 和 optional }
對(duì)象接口
Python 是動(dòng)態(tài)類型的語(yǔ)言,C++是靜態(tài)類型的。Python變量可能是:integer,float ,list ,dict,tuple,str,long,等等,還有其他類型。從Boost.Python和C++的觀點(diǎn)來(lái)看,Python中的變量是類object的實(shí)例,在本節(jié),我們看一下如何處理Python對(duì)象。
基本接口
// init optional #include<string> #include<iostream> #include<boost/python.hpp> #include <numpy/arrayobject.h> 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<dict>(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數(shù)組對(duì)象,讓C++進(jìn)行處理 int add_arr_1(object & data_obj, object rows_obj, object cols_obj) { PyArrayObject* data_arr = reinterpret_cast<PyArrayObject*>(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 調(diào)用:
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
總結(jié):
以上就是這篇文章的全部?jī)?nèi)容了,希望本文的內(nèi)容對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,如果有疑問(wèn)大家可以留言交流,謝謝大家對(duì)億速云的支持。
免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。