Skip to content

Instantly share code, notes, and snippets.

@fromradio
Last active August 21, 2019 08:24
Show Gist options
  • Save fromradio/bf0b33d84b6c6a4808de to your computer and use it in GitHub Desktop.
Save fromradio/bf0b33d84b6c6a4808de to your computer and use it in GitHub Desktop.
Boost.Python 使用笔记

Python.Boost 学习笔记1

Python.Boost是让Python能够更直接自由的调用C++函数和类的库。这个库的产生是为了提高Python的效率。这里这个笔记介绍如何使用这样一个强大的工具。

安装指南

笔者使用homebrew管理包,之前使用homebrew安装了2.7.9版本(这使得后面出现了cmake错误,后面再说)。首先安装boost库

brew install boost

接着安装Python.Boost

brew install boost-python

这里笔者安装的为1.59.0版本的boost和对应的Python.Boost

Hello World

首先介绍如何写一个Python.Boost的Hello World。在代码中我们使用C++实现一个返回字符串 "hello, world" 的函数并将其添加到模块中,C++函数如下:

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

我们希望将其转化为Python能调用的包,这里我们要使用Boost.Python的功能,将greet函数定义为python能够调用的函数

#include <boost/python/mudule.hpp>
#include <boost/python/def.hpp>
BOOST_PYTHON_MODULE(hello) {
    using namespace boost::python;
    def("greet", greet);
};

这里应该是用到了Boost.Python中定义的宏来进行转化,具体内容以后会仔细研读。 之后就是编译的需要,这里使用cmake,没有采用boost的bjam,具体是因为对于bjam还不熟,cmake比较熟悉一点。

cmake_minimum_required(VERSION 2.8.3)
FIND_PACKAGE(PythonInterp)
FIND_PACKAGE(PythonLibs)
FIND_PACKAGE(Boost COMPONENTS python)

上面会自动需找所需要的一些包,然后可以添加子目录,比如我们将上面的hello.cpp放在hello-world目录下,我们就添加如下子目录

ADD_SUBDIRECTORY(hello-world)

hello-world目录下我们插入如下cmake命令

PYTHON_ADD_MODULE(hello hello.cpp)

这样按照平常的cmake习惯进行配置编译即可

brew管理下的特殊命令

如果之前使用brew安装过Python并且使用brew管理boost库,可能会出现在使用Python调用自己所写的类的时候出现错误,这是因为cmake找到的Python库为系统自带的库而非brew编译的库,这时候需要在cmake的时候加入指定Python的命令,以2.7为例:

cmake -DPYTHON_LIBRARY=/usr/local/Cellar/python/2.7.9/Frameworks/Python.framework/Versions/2.7/lib/libpython2.7.dylib

后面在如平常加入路径

备注

  • 需要注意cpp文件中BOOST_PYTHON_MODULE后面的名字需要和cmake中的PYTHON_ADD_MODULE保持一直,否则会报init函数的错误
  • 不知道为什么如果不include的时候会报错。

Python.Boost 学习笔记2#

这次接着上次的内容继续,主要介绍如何转化C++的类为Python的类。

Hello World类

上次我们定义了一个greet函数,返回字符串hello, world。这次,我们先将这个函数封装到类World里面,希望得到如下这样的接口

x = World()
print x.greet()

而能得到结果

>>> hello, world

我们知道在c++中实现这样一个类是这样的

#include <string>

struct World {
    std::string greet() {
        return "hello, world";
    }
};

下一步将其转化为Python的类

#include <boost/python.hpp>
BOOST_PYTHON_MODULE(world) {
    class_<World>("World")
        .def("greet", &World::greet)
    ;
}

注意到和之前不同在于先使用boost::python中的class_类将我们的World转化为目标,之后使用def定义成员函数。

访问成员变量

类似于成员函数我们还可以访问C++类的成员变量,虽然这不是C++所鼓励的行为。比如我们试着定义一个字符串name和一个浮点数value,其中name是只读变量,而value是可读写的变量

struct World {
    void set(std::string n) {
        name = n;
    }
    std::string name;
    double value;
};

而转化的代码为

BOOST_PYTHON_MODULE(hello) {
    class_<World>("World")
        .def("set", &World::set)
        .def_readonly("name", &World::name)
        .def_readwrite("value", &World::value)
    ;
}

这样在Python中可以调用成员变量name和value

world = World()
world.set("hello, world")
print world.name
world.value = 3.14
print world.value

上述代码中将得到一个由C++编写的类,可以通过set给name赋值,而且内部变量value是可读可写。

构造函数

C++的构造函数也可以继承到Python中,比如定义了如下的构造函数

struct World {
    World(std::string n):name(n) {}
    void print() {
        std::cout << "The name is " << name << std::endl;
    }
private:
    std::string name;
};

BOOST_PYTHON_MODULE (constructor) {
    class_<World> ("World", init<>())
        .def("print", &World::print)
    ;
}

Boost.Python中,使用init作为构造函数的关键词,上面的代码在构造函数中将对应类的构造函数作为参数传入,但也可以通过如下的def传入。

def(init<>())

init的参数模板为构造函数的参数类型,比如构造函数的参数为(double x, double y),则初始化为

def(init<double,double>())

继承

TODO

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment