2016年1月6日 星期三

python call C++ API by Boost~初體驗

原則上,是將c++編譯成dll檔。
只是這個dll檔,是要給python用的

建立專案檔

建立一個Win32 Console的dll檔專案

原本的C++程式碼

先來看看一個cpp原本的code

.h檔

#include <string>
#include <map>

class Persion
{
std::string m_Name;
std::string m_HomeNumber;
public:
Persion();
explicit Persion(const std::string &name);
virtual ~Persion();
void SetName(const std::string &name);
std::string GetName() const;
void SetHomeNumber(const std::string &number);
std::string GetHomeNumber() const;
};

class PersionWithCell : public Persion
{
std::string m_CellNumber;
public:
PersionWithCell();
explicit PersionWithCell(const std::string &name);
void SetCellNumber(const std::string &number);
std::string GetCellNumber() const;
};

class PhoneBook
{
std::map<std::string, Persion*> m_PhoneBook;
public:
int GetSize() const;
void AddPerson(Persion *p);
void RemovePersion(const std::string &name);
Persion *FindPerison(const std::string &name);
};

.cpp檔

#include "phonebook.h"

Persion::Persion():
m_Name(""), m_HomeNumber("")
{}

Persion::Persion(const std::string &name):
m_Name(name), m_HomeNumber("")
{}

void Persion::SetName(const std::string &name)
{
m_Name = name;
}

std::string Persion::GetName() const
{
return m_Name;
}

void Persion::SetHomeNumber(const std::string &number)
{
m_HomeNumber = number;
}

std::string Persion::GetHomeNumber() const
{
return m_HomeNumber;
}

Persion::~Persion()
{}

int PhoneBook::GetSize() const
{
return (int)m_PhoneBook.size();
}

void PhoneBook::AddPerson(Persion *p)
{
m_PhoneBook[p->GetName()] = p;
}

void PhoneBook::RemovePersion(const std::string &name)
{
m_PhoneBook.erase(name);
}

Persion *PhoneBook::FindPerison(const std::string &name)
{
return m_PhoneBook[name];
}

void PersionWithCell::SetCellNumber(const std::string &number)
{
m_CellNumber = number;
}

std::string PersionWithCell::GetCellNumber() const
{
return m_CellNumber;
}

PersionWithCell::PersionWithCell():m_CellNumber(""), Persion()
{}

PersionWithCell::PersionWithCell(const std::string &name):m_CellNumber(""), Persion(name)
{}

為C++ code 建立表皮

再來我們為了這一個cpp程式,建立一份「皮」
在此可以注意的是,如果你要為屬性設定get/set,使用.add_property(),如果是只有get或只有set,就如同新增一個function一樣,用.def()
#include "phonebook.h"
#include <boost/python.hpp>

using namespace boost::python;

static std::string PrintPersion(const Persion &p)
{
std::ostringstream stream;
stream << p.GetName() << ": " << p.GetHomeNumber();
return stream.str();
}

std::ostream &operator<<(std::ostream &os, const Persion &p)
{
os << p.GetName() << ": " << p.GetHomeNumber();
return os;
}

BOOST_PYTHON_MODULE(phonebook)
{
class_<Persion>("Persion", init<>())
.def(init<std::string>())
.add_property("name", &Persion::GetName, &Persion::SetName)
.add_property("home_number", &Persion::GetHomeNumber, &Persion::SetHomeNumber)
.def("__str__", &PrintPersion)
.def(self_ns::str(self))
;

class_<PhoneBook>("PhoneBook")
.def("size", &PhoneBook::GetSize)
.def("add_persion", &PhoneBook::AddPerson)
.def("remove_persion", &PhoneBook::RemovePersion)
.def("find_persion", &PhoneBook::FindPerison,
return_value_policy<reference_existing_object>())
;
}


編譯

編譯成.dll檔!

用python呼叫之前


  1. 將.dll改成.pyd
  2. 將.pyd檔的檔名設定成BOOST_PYTHON_MODULE()裡定義的名字
  3. 將Boost的boost_python-vc80-mt-gd-1_60.dll copy 到和.py檔同目錄
    (這一步如果有人知道怎麼不移動檔案,還麻煩請告訴我呢!)

寫python

import debug.phonebook as phonebook

book = phonebook.PhoneBook()
p = phonebook.Persion()
p.name = "Chris"
p.home_number = '(123) 456-7890'
book.add_persion(p)
p = phonebook.Persion('Mary')
#p.name = 'Mary'
p.home_number = '(123) 456-7890'
book.add_persion(p)
print('No. of contacts =', book.size())
print(book.find_persion('Mary').home_number)
print(p)
print('--------')
import debug.phonebook as phonebook
p = phonebook.Persion('Mary')
print(p)
p.home_number = '(123) 456-7890'
print(p)

def persion_str(self):
return "Name: %s\nHome: %s" % (self.name, self.home_number)

phonebook.Persion.__str__ = persion_str
p = phonebook.Persion()
p.name = "Chris"
p.home_number = "(123) 456-7890"
print (p)

book = phonebook.PhoneBook()

class PyPersionWithCell(phonebook.Persion):
def get_cell_number(self):
return self.cell
def set_cell_number(self, n):
cell = n
celll_number = property(get_cell_number, set_cell_number)

p = PyPersionWithCell()
p.name = 'Martin'
p.home_number = '(123) 456-7890'
p.celll_number = '(123) 097-2134'
p2 = book.find_persion('Martin')
print(p2)

執行pythony就可以看見結果啦!

沒有留言:

張貼留言