C++、Python混合编程

文章目录

  • 安装C++中的python扩展模块
  • 使用C++编写python模块
    • STL适配扩展
    • 类适配扩展
  • 参考文献

安装C++中的python扩展模块

Python本身有着C接口,可以用C语言编写扩展模块,提供这个扩展的就是pybind11,有了它我们就能使用C++来开发Python扩展了。

首先我们需要在centos环境下安装这个库,使用以下命令:

sudo yum -y install python3-devel
sudo yum -y install python3-pip
pip3 install pytest
pip3 install pybind11

ubuntu环境下使用以下命令:

sudo apt-get install python3-dev
sudo apt-get install python3-pip
pip3 install pytest
pip3 install pybind11

使用C++编写python模块

在C++中,只需要使用一个宏PYBIND11_MODULE,其宏原型如下:

/**
 * @brief python 扩展模块
 * moudle_name 扩展名称,可以使用python语法import导入
 * module python::module实例对象,封装了所有操作
 */
PYBIND11_MODULE(module_name,module); // 定义Python模块

一个简单的例子如下,其定义了一个C++函数info,其会打印C++的环境信息。然后我们将其添加到pybind11之中。另外再定义一个有参的函数add,其计算两数之和。

#include 

namespace py = pybind11; // 名字空间别名,简化代码

PYBIND11_MODULE(pydemo, m) // 定义Python模块pydemo
{
    m.def("info", // 定义Python函数
          []()    // 定义一个lambda表达式
          {
              py::print("c++ version =", __cplusplus); // pybind11自己的打印函数
              py::print("gcc version =", __VERSION__);
              py::print("libstdc++   =", __GLIBCXX__);
          });
    m.def("add",           // 定义Python函数
          [](int a, int b) // 有参数的lambda表达式
          {
              return a + b;
          });
} // Python模块定义结束

之后,我们使用如下代码进行编译:

g++ main.cpp -std=c++11 -shared -fPIC  `python3 -m pybind11 --includes` -o pydemo`python3-config --extension-suffix`

这个编译代码较为复杂,我们来解释以下:

# 最后" "编译出来的文件"`python3-xxxxxxxx  "不要有空格,这个是规约,要不python找不到扩展
gcc "需要编译的文件" -std=c++11 -shared -fPIC  `python3 -m pybind11 --includes` -o "编译出来的文件"`python3-config --extension-suffix`

最后,我们编写如下的python脚本:

import pydemo

pydemo.info()
x=pydemo.add(1,2)
print(x)

测试结果如下:

[ik@localhost test]$ python3 test.py 
c++ version = 201103
gcc version = 7.5.0
libstdc++   = 20191114
3

STL适配扩展

pybind11也支持函数的参数和返回值使用标准容器,会自动转换成python中的list和dict。不过需要包含头文件stl.h下面是一个例子:

#include 
#include 
#include 
using namespace std;

namespace py = pybind11;

PYBIND11_MODULE(pydemo,module)
{
    module.def("use_str",
               [](const string &str)
               {
                   py::print(str);
                   return str + "!";
               });
    module.def("use_tuple",
               [](tuple<int, int, string> tu)
               {
                   get<0>(tu)++;
                   get<1>(tu)++;
                   get<2>(tu) += "?";
                   return tu;
               });
    module.def("use_list",
               [](vector<int> &vec)
               {
                   py::print("input: ", vec);
                   vec.push_back(100);
                   return vec;
               });
}

python直接调用C++写好的函数就可以了:

import pydemo

list_=[0,1,2,3]
# use_list 传入list被转换成vector
ret_list = pydemo.use_list(list_)
print("ret list: "+str(ret_list))

str_="hello world"
ret_str = pydemo.use_str(str_)
print("ret str: "+ret_str)

tuple_=(0,1,"hello")
ret_tuple=pydemo.use_tuple(tuple_)
print("ret tuple: "+str(ret_tuple))

结果如下:

[ik@localhost test]$ python3 test.py
input:  [0, 1, 2, 3]
ret list: [0, 1, 2, 3, 100]
hello world
ret str: hello world!
ret tuple: (1, 2, 'hello?')

类适配扩展

C++中的类也可以等价转换到Python中进行调用,这需要用到一个特别的模板类class_。下面是个例子:

#include 

namespace py = pybind11;
class Point final
{
public:
    Point(int a)
    {
        x = a;
    }
    Point()
    {
        Point(0);
    }

public:
    int get() { return x; }
    void set(int a)
    {
        x = a;
    }

private:
    int x;
};

PYBIND11_MODULE(pydemo, m)
{
    py::class_<Point>(m, "Point")
        .def(py::init())
        .def(py::init<int>())
        .def("get", &Point::get)
        .def("set", &Point::set);
};

python中直接调用就可以了:

import pydemo

point = pydemo.Point(1);
print(point.get())

最终输出结果如下:

[ik@localhost test]$ python3 test.py
1

参考文献

[1] 罗剑锋.罗剑锋的C++实战笔记.极客时间

你可能感兴趣的:(#,C++高级,#,python,c++,python,开发语言)