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就可以看見結果啦!

沒有留言:

張貼留言

(什麼是留言欄訊息?)