你将学到什么

  • 如何在Python中调用C++代码
  • 如何在C++中调用Python代码

在Python中调用C++代码

首先定义一个动物类(include/animal.h)

#pragma once

#include <string>

class Animal
{
public:
Animal(std::string name);
virtual ~Animal(); virtual void call();
virtual void move();
void eat(std::string food); protected:
std::string name_;
};

其实现代码如下(src/animal.cpp)

#include <iostream>
#include "animal.h" Animal::Animal(std::string name):name_(name)
{
} Animal::~Animal()
{
} void Animal::call()
{
std::cout << name_ << ": call" << std::endl;
} void Animal::move()
{
std::cout << name_ << ": moving" << std::endl;
} void Animal::eat(std::string food)
{
std::cout << name_ << ": eat " << food << std::endl;
}

接着编写其导出代码(include/boost_wrapper.h)

#pragma once

#include <boost/python/wrapper.hpp>
#include "animal.h" class AnimalWrap: public Animal, public boost::python::wrapper<Animal>
{
public:
AnimalWrap(std::string name);
virtual ~AnimalWrap(); void call();
void move();
};

其导出实现如下(src/boost_wrapper.cpp)

#include <boost/python/module.hpp>
#include <boost/python/class.hpp>
#include "boost_wrapper.h" using namespace boost::python;
using namespace boost::python::detail; AnimalWrap::AnimalWrap(std::string name):Animal(name)
{
} AnimalWrap::~AnimalWrap()
{
} void AnimalWrap::call()
{
if (override func = this->get_override("call"))
func();
Animal::call();
} void AnimalWrap::move()
{
if (override func = this->get_override("move"))
func();
Animal::move();
} BOOST_PYTHON_MODULE_INIT(boost)
{
class_<AnimalWrap, boost::noncopyable>("Animal", init<std::string>())
.def("call", &Animal::call)
.def("move", &Animal::move)
.def("eat", &Animal::eat);
}

最后编写CMakeLists.txt

cmake_minimum_required(VERSION 2.8)
project(boost) set(CMAKE_CXX_FLAGS "-Wall -g") ### 此处的动态库名必须和BOOST_PYTHON_MODULE()中定义的保持一致,即最后生成的库必须名为boost.so
file(GLOB SRC "src/*.cpp")
add_library(boost SHARED ${SRC})
set_target_properties(boost PROPERTIES PREFIX "") #dependencies
INCLUDE(FindPkgConfig)
pkg_check_modules(PYTHON REQUIRED python)
include_directories(include /usr/local/include ${PYTHON_INCLUDE_DIRS})
link_directories(/usr/local/lib ${PYTHON_LIBRARY_DIRS})
target_link_libraries(boost boost_python)

项目最终目录结构

# tree .
.
├── build
├── CMakeLists.txt
├── include
│ ├── animal.h
│ └── boost_wrapper.h
└── src
├── animal.cpp
└── boost_wrapper.cpp 3 directories, 5 files

编译

# cd build
# cmake ..
# make

编写测试文件(build/zoo.py)

import boost

def show():
wolf = boost.Animal("wolf")
wolf.eat("beef")
goat = boost.Animal("gota")
goat.eat("grass") if __name__ == '__main__':
show()

执行测试

# cd build
# python zoo.py
wolf: eat beef
gota: eat grass

在C++中调用Python代码

在上个项目的根目录添加源文件(main.cpp)

#include <iostream>
#include <boost/python.hpp> using namespace boost::python; int main()
{
Py_Initialize();
if (!Py_IsInitialized())
{
std::cout << "Initialize failed" << std::endl;
return -1;
} try
{
object sys_module = import("sys");
str module_directory(".");
sys_module.attr("path").attr("insert")(1, module_directory);
object module = import("zoo");
module.attr("show")();
}
catch (const error_already_set&)
{
PyErr_Print();
}
Py_Finalize();
return 0;
}

修改CMakeLists.txt

cmake_minimum_required(VERSION 2.8)
project(boost) set(CMAKE_CXX_FLAGS "-Wall -g") ### 此处的动态库名必须和BOOST_PYTHON_MODULE()中定义的保持一致,即最后生成的库必须名为boost.so
file(GLOB SRC "src/*.cpp")
add_library(boost SHARED ${SRC})
set_target_properties(boost PROPERTIES PREFIX "")
add_executable(core main.cpp) #dependencies
INCLUDE(FindPkgConfig)
pkg_check_modules(PYTHON REQUIRED python)
include_directories(include /usr/local/include ${PYTHON_INCLUDE_DIRS})
link_directories(/usr/local/lib ${PYTHON_LIBRARY_DIRS})
target_link_libraries(boost boost_python)
target_link_libraries(core boost ${PYTHON_LIBRARIES})

编译并执行测试

# cd build
# cmake ..
# make
# ./core
wolf: eat beef
gota: eat grass

总结

考虑这样一个需求,我们要展示一个动物园中的动物,但是动物的种类和个数都不固定,这就导致我们动物园的show方法需要经常变动,有什么办法可以避免程序的反复编译呢?一种方式就是使用配置文件,将需要展示的动物写入配置文件,然后动物园的show方法通过解析配置文件来生成需要展示的内容;另一种方式就是通过Python脚本来实现,因为Python脚本不需要编译,相比于配置文件的方式,Python脚本的方式不需要设计配置文件格式,也不需要实现复杂的解析逻辑,使用起来更加灵活。

在上面的例子中,我们使用Python脚本实现了原本应该在main.cpp中实现的show方法,然后在main.cpp中调用它,后面如果有改动我们直接修改Python脚本即可,无需重编程序。

Boost Python学习笔记(二)的更多相关文章

  1. python学习笔记(二)、字符串操作

    该一系列python学习笔记都是根据<Python基础教程(第3版)>内容所记录整理的 1.字符串基本操作 所有标准序列操作(索引.切片.乘法.成员资格检查.长度.最小值和最大值)都适用于 ...

  2. Python 学习笔记二

    笔记二 :print 以及基本文件操作 笔记一已取消置顶链接地址 http://www.cnblogs.com/dzzy/p/5140899.html 暑假只是快速过了一遍python ,现在起开始仔 ...

  3. Boost Python学习笔记(四)

    你将学到什么 在Python中调用C++代码时的传参问题 基础类型 Python的字符串是常量,所以C++函数参数中的std::string &必须为const 修改源文件(main.cpp) ...

  4. Boost Python学习笔记(五)

    你将学到什么 在C++中调用Python代码时的返回值问题 基础类型 修改Python脚本(build/zoo.py) def rint(): return 2 def rstr(): return ...

  5. Boost Python学习笔记(三)

    你将学到什么 在C++中调用Python代码时的传参问题 基础类型 继续使用前面的项目,但是先修改下Python脚本(zoo.py),添加Add和Str函数,分别针对整数.浮点数和字符串参数的测试 d ...

  6. (10.1)Python学习笔记二

    1.在项目工程中要模块化测试一个开发的功能,在测试通过后交付给项目组其他人员继续开发.要保证代码开发的性能和效率以及可扩展性. 2.项目工程中的文件夹分类要功能模块明确清晰,在python中引入某一个 ...

  7. Python学习笔记二

    ---恢复内容开始--- 一. python几种数据类型的比较. 从以下几个方面比较: 1. 是否可变. 不可变类型:变量的值可以发生变化,id也变了,相当于创建了一个新的对象,所以一修改值,id就变 ...

  8. Python学习笔记(二)

    标识符和关键字 1,邮箱的Python标识符是任意长度的非空字符序列(引导字符+后续字符.) python标识符必须符合两条规则--标识符区分大小写 (1)只要是unicode编码字母都可以充当引导字 ...

  9. python学习笔记(二):python数据类型

    上一篇博客写了python的入门和简单流程控制,这次写python的数据类型和各种数据类型的内置方法.一.数据类型是什么鬼?计算机顾名思义就是可以做数学计算的机器,因此,计算机程序理所当然地可以处理各 ...

随机推荐

  1. window.onload 添加多个函数绑定

    window.onload = function(){alert(2)} function addEvent (fun) { var old = window.onload; if(typeof ol ...

  2. 英语发音规则---ea字母组合发音规律

    英语发音规则---ea字母组合发音规律 一.总结 一句话总结:字母组合ea的发音规律,在学习字母组合在单词中的发音规律以前,一定要熟练撑握什么是开音节,什么是闭音节,否则你就不撑握这些发音规律. ea ...

  3. js文件报错Syntax error on token "Invalid Regular Expression Options", no accurate correction

    Syntax error on token "Invalid Regular Expression Options", no accurate correction 1.选中报错的 ...

  4. mySQL 5.7版 解决密码登录失败Access denied for user 'root'@'localhost' (us

    mySQL 5.7版 解决密码登录失败Access denied for user 'root'@'localhost' (us             2016-03-05              ...

  5. 备忘录One

    1.POI操作excel技术博客记录 2.SSH框架搭建记录 3.SSM框架搭建记录 4.文件上传下载记录 5.面试题整理

  6. bootstrap 左右框多项选择示例

    bootstrap 左右选择框,左边框是未选项,右边框是已选择项,提供单选,全选按钮,以及取消已选项,如图示:

  7. 非系统表空间损坏,rman备份恢复

    实验条件:有完整可用备份--查询表空间情况SQL> select tablespace_name,status from dba_tablespaces;TABLESPACE_NAME STAT ...

  8. spark减少提交jar包处理

    spark一个应用,算上依赖一百多兆.每一次都如此,坑. 首先是<packing>jar</packing>这只为打包为jar,在plugin中增加一个assembly插件,这 ...

  9. bzoj 4006 管道连接 —— 斯坦纳树+状压DP

    题目:https://www.lydsy.com/JudgeOnline/problem.php?id=4006 用斯坦纳树求出所有关键点的各种连通情况的代价,把这个作为状压(压的是集合选择情况)的初 ...

  10. Android HttpGet和HttpPost设置超时

    HttpPost: private Runnable runnable = new Runnable() { @Override public void run() { String url = Ba ...