Boost.Python使用小结

来源:http://blog.csdn.net/KongDong

作者:fasiondog

 

万事开头难!前段日子因为性能问题升级了机器,程序语言也从python转到了C++,不过因为数据分析的问题,还是交互式的环境用着方便,于是埋头又将编好的C++库切回python,不过这一回用的是Boost.Python,刚开始编译总是有问题,查看文档才发现Boost.Python中的构建说明帮助不够完全,如果没仔细学习Boost.Build的话,要按自己的方式编译的话还是很麻烦。费劲力气之后,终于把程序库的编译架子搭起来,之后就势如破竹了,现在使用Boost.Python真的很畅快。一辆没钥匙的新车,开不起来是多么恼火的事情啊!如果希望使用Boost.Python,而卡在起点不能前进,那滋味真不好受:(

 

下面简单总结一下使用Boost.Python建立自己的编译工程的方法,便于快速进入Boost.Python。其实,建立自己的编译工程主要的问题就是Boost.Build涉及的多个配置文件,而在Boost.Python的构建说明文档中说的不全面,导致总是被卡。下面的红色字体部分是我的注释说明。

(注:我的编译环境是linux + gcc)

 

1、在用户根目录下建立user-config.jam文件,如下:

 

 #  MSVC configuration

using gcc ;



# Python configuration

using python : 2.6 : /usr ;

 

 

2、在CPP文件工作目录下,建立boost-build.jam,如下:

 


# Copyright David Abrahams 2006. Distributed under the Boost




# Software License, Version 1.0. (See accompanying




# file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)






# Edit this path to point at the tools/build/v2 subdirectory of your




# Boost installation.  Absolute paths work, too.




boost-build /home/fasiondog/src/boost_1_42_0/tools/build/v2 ;   #指明Boost库构建的位置,需自行修改


3、在CPP文件工作目录下,建立Jamroot文件,如下:

 

#这是Boost.Python的示例,需要修改哪些地方,请往后一例子

# Copyright David Abrahams 2006. Distributed under the Boost




# Software License, Version 1.0. (See accompanying




# file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)






import python ;






if ! [ python.configured ]




{




    ECHO "notice: no Python configured in user-config.jam" ;




    ECHO "notice: will use default configuration" ;




    using python ;




}






# Specify the path to the Boost project.  If you move this project,




# adjust this path to refer to the Boost root directory.




use-project boost




  : /home/fasiondog/src/boost_1_42_0 ;






# Set up the project-wide requirements that everything uses the




# boost_python library from the project whose global ID is




# /boost/python.




project




  : requirements <library>/boost/python//boost_python ;






# Declare the three extension modules.  You can specify multiple




# source files after the colon separated by spaces.




python-extension hello_ext : hello.cpp ;






# A little "rule" (function) to clean up the syntax of declaring tests




# of these extension modules.




local rule run-test ( test-name : sources + )




{




    import testing ;




    testing.make-test run-pyd : $(sources) : : $(test-name) ;




}






# Declare test targets




run-test hello : hello_ext hello.py ;


自己用的一个Jamroot实例:

 

 

# Copyright David Abrahams 2006. Distributed under the Boost

# Software License, Version 1.0. (See accompanying

# file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)



import python ;



if ! [ python.configured ]

{

    ECHO "notice: no Python configured in user-config.jam" ;

    ECHO "notice: will use default configuration" ;

    using python ;

}



# Specify the path to the Boost project.  If you move this project,

# adjust this path to refer to the Boost root directory.

use-project boost

  : /home/fasiondog/src/boost_1_42_0 ;



# Set up the project-wide requirements that everything uses the

# boost_python library from the project whose global ID is

# /boost/python.

project

  : requirements <library>/boost/python//boost_python

  ;

 

#注意下面这一段,指明工程依赖的库/头文件/编译器的编译选项等等

project : requirements <library>/usr/lib/libgalaxy.so ;   #指明依赖的外部共享库

project : requirements <include>/home/fasiondog/workspace/galaxy ;
#指明依赖的外部库头文件

project : requirements <cxxflags>-std=c++0x ;  
#编译器编译选项

#project : requirements <cxxflags>-fno-inline ;
#编译器编译选项



# Declare the three extension modules.  You can specify multiple

# source files after the colon separated by spaces.

#指明编译的目标输出,可以指明多个目标,下面要求输出两个目标: _cstock 和 _indicator.so,注意可以使用目录方式输出

python-extension _cstock : main.cpp

         _DataType.cpp

         _DataRecord.cpp

         _DataQuery.cpp

         _KData.cpp

         _Stock.cpp

         _StockManager.cpp ;




python-extension indicator/_indicator : indicator/_Indicator.cpp




         indicator/_Indicator_main.cpp


;




# A little "rule" (function) to clean up the syntax of declaring tests

# of these extension modules.

#local rule run-test ( test-name : sources + )

#{

#    import testing ;

#    testing.make-test run-pyd : $(sources) : : $(test-name) ;

#}



# Declare test targets

#run-test hello : hello_ext hello.py ;

 

 

 

4、在CPP文件工作目录下,直接运行bjam,默认编译成Debug版本,运行bjam release生成Release版本


 

下面是使用Eclipse编译的方法,供参考,优点是编译时按快捷键立即执行编译检查错误,缺点是编译多目标时不方便

 

不使用Boost.Build工具的编译方法,在Eclipse中编译:(注:bjam可以同时编译多个目标,Eclipse做同样的事得建多个工程,目录结构会不清晰,并不比bjam方便,但编写代码时可以直接按快捷键进行编译快速检查错误,我的方法是在Eclipse中建一个工程,Jamroot里指定多目标,用Eclipse进行编译检查,编译通过后,最后再运行bjam编译并拷贝目标至相应目录)

 

Boost.Python使用小结

 

Boost.Python使用小结

 

Boost.Python使用小结

 

Boost.Python使用小结

 


 

其他一些Boost.Python使用问题:

 

def(str(self) 无法编译问题:

必须改写成def(self_ns::str(self))

或者使用下面的函数方式:

  .def("__str__", &MultiBoolean::ToString)


注册boost::shared_ptr:

register_ptr_to_python<boost::shared_ptr<XXXX> >();


引出迭代子:

.def("__iter__", iterator<StockManager>())

这里的iterator仅要求类具有 iterator::begin 和 iterator::end 成员函数即可,不需要C++迭代子中一大堆定义,很方便


虚函数和默认参数在boost帮助中写的很清楚

对于继承关系使用 class_<AAAA, bases(AAAABase)>("AAAA");  即使AAAABase已经使用了wrapper包装也没关系


Boost.Python已经解决了默认参数的问题,对于python中的命名参数,可以在python中使用函数直接包装一层即可,如下:

def KData_iter(kdata):

    for i in range(len(kdata)):

        yield kdata[i]

KData.__getitem__ = KData_getitem


对于初始化函数的命名参数可以使用python继承包装,如下:

class Query(DataQuery):

    def __init__(self, start = 0, end = DataQuery.NoneType.NONE, queryType = DataQuery.QueryType.INDEX,

                 dataType=DataQuery.DataType.DAY, recoverType = DataQuery.RecoverType.NO_RECOVER):

        super(Query, self).__init__(start, end, queryType, dataType, recoverType)


简单引出std::vector容器,让其具有和python list类似的功能(不含切片)(下面的DataRecordList = std::vector<DataRecord>):

    DataRecordList::const_reference (DataRecordList::*DataRecordList_at)(DataRecordList::size_type) const = &DataRecordList::at;

    class_<DataRecordList>("RecordList")

            .def("__iter__", iterator<DataRecordList>())

            .def("__len__", &DataRecordList::size)

            .def("__getitem__", DataRecordList_at, return_value_policy<copy_const_reference>())

            ;


对如下C++用法, 在python中继承同名重载_func运行正常:

class Base{

public:

    int func_wrap() { return _func(); }

protected:

    virtual int _func() = 0;

};

class T: public Base{

private:

    int _func(){ return 100; }

};

在python中:

class T(Base):

    def _func(self):

        return 100

 

 

===================================================

20100228 补充:

如何在Python中使用boost::any?

一个C++基类示例:

class TestBase{

public:

    boost::any getParam(const std::string& name, const boost::any& value);

    bool setParam(const std::string& name, const boost::any& value);

   ……

};

 

通过普通的方式虽然可以引出getParam和setParam函数,但在python中却因boost::any存放类型不可知无法使用,可以按下面的方法解决,但是此时boost::any只能支持有限的类型。还有一种方法通过定义右值转换器,但是这种方法由于boost::any跨越共享库边界时,type_info(boost::any<XX>).name在不同的库中不一致,必须使用非安全转换,暂时不可取。

 

 

/*

 * 定义boost::any To python转换,接近TestBase::getParam问题

 */

struct AnyToPython{
    static PyObject* convert(boost::any x) {
        if( size_t *sizet = boost::any_cast<size_t>(&x)){
            return Py_BuildValue("n", *sizet);
        }else if( double *d = boost::any_cast<double>(&x)){
            return Py_BuildValue("d", *d);
        }else{
            std::cerr << "convert failed! Unkown type! Will return None! Please modify AnyToPython" << std::endl;
            return Py_BuildValue("s", (char *)0);
        }
    }
};

 

/*

 * 新定义一个普通函数,包装原TestBase::setParam函数,注意第一个、第三个参数

 * 需要在python文件中,对Test.setParam复制,而不是在这里直接引出Test::setParam函数

 */

bool setParam(const boost::shared_ptr<TestBase>& indicator, const std::string& name, object o){
    boost::any tmp;
    extract<size_t> x1(o);
    if( x1.check() ){
         tmp = x1();
        indicator->setParam(name, tmp);
        return true;
    }

    extract<double> x2(o);
    if( x2.check() ){
        tmp = x2();
        indicator->setParam(name, tmp);
        return true;
    }

    return false;
}

BOOST_PYTHON_MODULE(_test){

    class_<TestBase>("Test")

        .def("getParam", &TestBase.getParam)

        ;

 

    to_python_converter<boost::any, AnyToPython>();

    def("setParam", setParam);

}

 

在相应的python文件中(如test.py):

from _test import *

Test.setParam = setParam  #解决Test::setParam问题

原文链接: https://www.cnblogs.com/hainange/archive/2010/02/25/6153672.html

欢迎关注

微信关注下方公众号,第一时间获取干货硬货;公众号内回复【pdf】免费获取数百本计算机经典书籍

    Boost.Python使用小结

原创文章受到原创版权保护。转载请注明出处:https://www.ccppcoding.com/archives/8379

非原创文章文中已经注明原地址,如有侵权,联系删除

关注公众号【高性能架构探索】,第一时间获取最新文章

转载文章受原作者版权保护。转载请注明原作者出处!

(0)
上一篇 2023年2月6日 下午7:20
下一篇 2023年2月6日 下午7:21

相关推荐