pybind11 allow us to expose c++ class/function to higher abstraction level of python programming language, bringing high performance and flexibility into python.
To pass named arguments in python, it’s required to specify argument names in pybind11’s interface. In this post, I will illustrate how to do that.
c++ class
header
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#include<pybind11/pybind11.h>#include<pybind11/embed.h>#include<pybind11/stl.h>#include<iostream>#include<cstdlib>#include<cstdio>// from SnailCore
#include<util/acct_info.hpp>#include<util/shm.hpp>#include<util/shm_tool.hpp>#include<util/shm_status.hpp>#include<util/shm_struct.hpp>#include<util/shmv.hpp>#include<util/time_util.hpp>#include<util/index_type.hpp>#include<util/str_util.hpp>
classAccount{public:Account(conststd::string&shm_tag,intshm_size,boolcontinued=false):_shm_tag{shm_tag},_shm_size{shm_size},_continued{false}{_shm_acc.reset(newacct_info_t::shm_writer_t(_shm_tag,_shm_size,_continued));}~Account(){}voidwrite(conststd::string&client_id,doublebeg_balance,doublecurr_balance,doubleenabled_balance,doublefrozen_balance=0.0,doubledeposit=0.0,doublemargin=0.0,doublefrozen_margin=0.0,doublefee=0.0,doublefrozen_fee=0.0,doublepos_profit=0.0,doubleclose_profit=0.0,uint64_tus=0){autoe=_shm_acc->get_slot();if(!e){std::cout<<"failed to get_slot, shm is full"<<std::endl;return;}e->us=us==0?microtime::now().count():us;copy_str(e->client_id,client_id.c_str());e->beg_balance=beg_balance;e->curr_balance=curr_balance;e->enabled_balance=enabled_balance;e->frozen_balance=frozen_balance;e->deposit=deposit;e->margin=margin;e->frozen_margin=frozen_margin;e->fee=fee;e->frozen_fee=frozen_fee;e->pos_profit=pos_profit;e->close_profit=close_profit;_shm_acc->commit(e);}py::dictread(){returnpybind11_read_shm_acc(_shm_tag);}private:std::string_shm_tag;int_shm_size{0};bool_continued{false};std::shared_ptr<typenameacct_info_t::shm_writer_t>_shm_acc;};
pybind11 interface
pybind11 provides by MACRO interfaces of c++. By defining py::arg("shm_tag"), it’s possible to pass named arguments from python into c++’s functions/classes, with default values setting.
PYBIND11_MODULE(snail,m){// Function Interface
m.def("pybind11_read_shm_acc",&pybind11_read_shm_acc,R"pbdoc(readsnail::acct_info_t)pbdoc");// Class Interface
// define Account class
py::class_<Account>(m,"Account")// ctor
.def(py::init<conststd::string&,int,bool>(),py::arg("shm_tag"),py::arg("shm_size"),py::arg("continued")=false).def("write",&Account::write,py::arg("client_id"),py::arg("beg_balance"),py::arg("curr_balance"),py::arg("enabled_balance"),py::arg("frozen_balance")=0.0,py::arg("deposit")=0.0,py::arg("margin")=0.0,py::arg("frozen_margin")=0.0,py::arg("fee")=0.0,py::arg("frozen_fee")=0.0,py::arg("pos_profit")=0.0,py::arg("close_profit")=0.0,py::arg("us")=0).def("read",&Account::read);#ifdef VERSION_INFO
m.attr("__version__")=MACRO_STRINGIFY(VERSION_INFO);#else
m.attr("__version__")="dev";#endif
}
python calling
Now we can call c++ functions/class interfaces in python.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
importpandasaspdfromwepy.cpp.snailimportpybind11_read_shm_accfromwepy.cpp.snailimportAccount## Function Interfacedefread_shm_acc(shm_tag:str)->pd.DataFrame:data=pybind11_read_shm_acc(shm_tag)returnpd.DataFrame(data)## Class Interfacefromwepy.cpp.snailimportAccountacct=Account(shm_tag="lfang_acc",shm_size=1000)acct.write(client_id="lfang",beg_balance=1000.0,curr_balance=1000.0,enabled_balance=1000.0,deposit=100)df=pd.DataFrame(acct.read())df=read_shm_acc("lfang_acc")