那么如何使用python调用自己编写的c++接口呢?原理很简单
原理简单,操作起来更简单,下面简单介绍一种搭建python调用c++工程的方法。
pybind11
pybind11
主要用于创建现有C++代码的Python绑定,是一个轻量级的仅头文件库。 源码见:https://github.com/pybind/pybind11
pybind11
可以直接使用pip
工具安装
pip3 install pybind11
编写c++代码包括两部分:
PYBIND11_MODULE
注册模块,并向外部暴露;举个例子,新建cpp文件Sample.cpp
#include
#include
int AddNums(int left, int right)
{
return left + right;
}
// 注册需要暴露给 python 的函数
PYBIND11_MODULE(mathDemo, m)
{
m.def("AddNums", &AddNums, "Call Add Sums Function");
}
编译c++代码并生成.so文件的方式有很多种,可以使用 gcc/g++ 命令,也可以使用 cmake 工具。本文使用的是python的包管理工具集setuptools
,在工程根目录下新建脚本setup.py
from setuptools import setup, Extension
mathDemo = Extension(
"mathDemo",
sources=["Sample.cpp"],
include_dirs=["/opt/homebrew/lib/python3.10/site-packages/pybind11/include"], # Note: 替换成 pybind11 头文件实际安装的位置
language="c++",
extra_compile_args=["-std=c++11", "-g"],
)
setup(
name='mathDemo',
version='0.1',
ext_modules=[mathDemo],
options={"install": {"install_lib": "lib"}}, # Note: 可选, 没指定 options["install"] 的话会安装到系统路径下,不妨碍使用
install_requires=['pybind11>=2.6'],
)
写好setup.py
后执行以下命令即可编译c++代码、生成so并自动安装到指定路径
python3 setup.py install
注:
setup.py
中的 options 是可选项,options[“install”]用于指定.so文件的安装位置。默认安装到系统路径下(可以使用pip3 freeze
命令查到)
调用c++接口与调用python模块的方法是一样的,编写python代码调用c++代码即可
import sys
sys.path.append("lib/mathDemo-0.1-py3.10-macosx-12-arm64.egg") # Note: 可选,如果选择安装在系统路径下,这里不需要指定 .so 路径
import mathDemo
value = mathDemo.AddNums(1, 3) # 调用 c++ 的 AddNums 接口
print(f"sum: {value}")
上面的例子很简单,入参和返回值都是基本数据类型,实际上pybind11
支持更复杂的数据类型,例如常见的std容器std::map
、std::vector
、std::set
以及字符串std::string
和自定义结构体。
std::string
可以直接与python的str转换std::vector
和std::map
可以直接与python的内置list和dict转换举个例子
c++代码
#include
#include
#include
#include
#include
std::vector<std::map<std::string, int>> MovePoints(std::vector<const std::map<std::string, int>>& pots, std::map<std::string, int> vect)
{
std::vector<std::map<std::string, int>> resPots(pots.size());
for (int index = 0; index < pots.size(); index++)
{
resPots[index]["x"] = pots[index].at("x") + offset.at("x");
resPots[index]["y"] = pots[index].at("y") + offset.at("y");
}
return resPots;
}
// 注册 MovePoints
PYBIND11_MODULE(test, m)
{
m.def("MovePoints", &MovePoints, "Call Move Points Function");
}
python代码
pots = [{"x": 1, "y": 4},
{"x": 2, "y": 5},
{"x": 3, "y": 6},
{"x": 4, "y": 7},
{"x": 5, "y": 8}]
offset = {"x": -1, "y": 1}
resPots = mathDemo.MovePoints(pots, offset)
print(f"{resPots}")