C++_python_相互之间的包含调用方法

1、C++的代码封装成插件或者封装成库,供python调用

C++ 代码完全可以封装成插件或库,供 Python 调用。这是 Python 生态中非常常见且成熟的做法,尤其在需要高性能计算、调用底层系统功能或复用已有 C/C++ 代码时。

以下是几种主流方法:

✅ 方法一:使用 pybind11(最推荐)

pybind11 是一个轻量级、现代的 C++ 库,专为将 C++ 代码暴露给 Python 而设计。语法简洁,支持 C++11 及以上特性(如类、重载、STL 容器等)。

示例步骤:

复制代码
编写 C++ 代码(example.cpp):
bash 复制代码
#include <pybind11/pybind11.h>

int add(int a, int b) {
    return a + b;
}

PYBIND11_MODULE(example, m) {
    m.doc() = "pybind11 example plugin";
    m.def("add", &add, "A function that adds two numbers");
}

编译为 Python 模块(使用 setup.py):

bash 复制代码
# setup.py
from setuptools import setup, Extension
from pybind11.setup_helpers import Pybind11Extension, build_ext

ext_modules = [
    Pybind11Extension(
        "example",          # 模块名
        ["example.cpp"],    # 源文件
    ),
]

setup(
    name="example",
    ext_modules=ext_modules,
    cmdclass={"build_ext": build_ext},
    zip_safe=False,
)

构建并安装:

bash 复制代码
pip install pybind11

python setup.py build_ext --inplace

在 Python 中调用:

bash 复制代码
import example
print(example.add(2, 3))  # 输出 5
复制代码
✅ 优点:开发简单、性能高、自动类型转换、支持复杂 C++ 特性
🔧 依赖:需安装 pybind11(pip install pybind11)

✅ 方法二:使用 Python C API(官方底层接口)

直接使用 Python 提供的 C API 编写扩展模块(.so 或 .pyd)。这是最底层的方式,但代码繁琐。

示例(简化):

bash 复制代码
// example.c
#include <Python.h>

static PyObject* add(PyObject* self, PyObject* args) {
    int a, b;
    if (!PyArg_ParseTuple(args, "ii", &a, &b))
        return NULL;
    return PyLong_FromLong(a + b);
}

static PyMethodDef methods[] = {
    {"add", add, METH_VARARGS, "Add two integers"},
    {NULL, NULL, 0, NULL}
};

static struct PyModuleDef module = {
    PyModuleDef_HEAD_INIT,
    "example",
    NULL,
    -1,
    methods
};

PyMODINIT_FUNC PyInit_example(void) {
    return PyModule_Create(&module);
}

然后用 setup.py 编译(类似上面,但不用 pybind11)。

✅ 优点:不依赖第三方库

❌ 缺点:代码冗长、易出错、需手动管理引用计数

✅ 方法三:使用 Cython

Cython 是 Python 的超集,可将 .pyx 文件编译为 C 扩展。你可以在 Cython 中调用 C/C++ 代码,并暴露给 Python。

适合场景:已有 C++ 代码,想通过中间层包装。

复制代码
✅ 优点:与 NumPy 集成好,适合数值计算
⚠️ 注意:需学习 Cython 语法

✅ 方法四:封装为 动态链接库 + ctypes / cffi

如果你不想生成 Python 扩展模块,也可以:

复制代码
将 C++ 函数用 extern "C" 导出为 C 接口(避免 C++ 名称修饰)
编译为 .so(Linux/macOS)或 .dll(Windows)
在 Python 中用 ctypes 或 cffi 加载调用

示例(C++ 端):

bash 复制代码
// mathlib.cpp
extern "C" {
    int add(int a, int b) {
        return a + b;
    }
}

编译:

bash 复制代码
g++ -shared -fPIC -o mathlib.so mathlib.cpp

Python 调用:

bash 复制代码
import ctypes
lib = ctypes.CDLL("./mathlib.so")
lib.add.argtypes = (ctypes.c_int, ctypes.c_int)
lib.add.restype = ctypes.c_int
print(lib.add(2, 3))  # 5
复制代码
✅ 优点:无需 Python 扩展构建系统,跨语言通用
❌ 缺点:只能导出 C 风格接口,不支持类、异常、STL 等 C++ 特性

五、 📌 总结对比

表格

方法 易用性 性能 支持 C++ 特性 适用场景
pybind11 ⭐⭐⭐⭐⭐ 完全支持(类、模板、STL) 首选方案
Python C API ⭐⭐ 需手动封装 底层开发/无第三方依赖
Cython ⭐⭐⭐ 有限支持 数值计算、与 NumPy 集成
ctypes/cffi ⭐⭐⭐ 仅 C 接口 快速调用简单函数

💡 建议

复制代码
新项目 → 优先用 pybind11
已有 C 函数库 → 用 ctypes 快速集成
高性能数值计算 → 考虑 Cython
嵌入式/受限环境 → 用原生 C API

2、python的代码封装成插件或者封装成库,供C++调用

Python 代码可以封装成库或插件供 C++ 调用,但通常需要借助一些特定的技术或工具。以下是几种主流方法:

方法一:使用 Python/C API(官方接口)

这是 Python 官方提供的 C 接口,C++ 可以通过它嵌入 Python 解释器并调用 Python 代码。

步骤简述:

复制代码
在 C++ 项目中链接 Python 的动态库(如 libpython3.x.so 或 python3x.lib)。
使用 Py_Initialize() 初始化解释器。
用 PyRun_SimpleString() 或 PyObject_CallObject() 等函数加载并调用 Python 模块/函数。
处理 Python 对象与 C++ 数据类型的转换。
最后调用 Py_Finalize() 清理。

示例(简化):

bash 复制代码
#include <Python.h>

int main() {
    Py_Initialize();
    PyRun_SimpleString("import sys; sys.path.append('.')");
    PyRun_SimpleString("import mymodule");
    PyRun_SimpleString("mymodule.my_function()");
    Py_Finalize();
    return 0;
}
复制代码
✅ 优点:直接、灵活
❌ 缺点:需手动管理引用计数、错误处理复杂、依赖 Python 环境

方法二:使用 pybind11(推荐)

虽然 pybind11 主要用于将 C++ 暴露给 Python,但它也支持反向操作------在 C++ 中嵌入 Python。

不过更常见的是:将核心逻辑写成 C++,用 pybind11 暴露给 Python;如果已有 Python 代码想被 C++ 调用,仍建议用 Python/C API 或生成可执行接口。

但 pybind11 本身不直接"让 C++ 调用任意 Python 函数"变得简单,它更擅长反向绑定。

方法三:将 Python 封装为 独立服务(进程间通信)

如果不想在 C++ 中嵌入 Python 解释器,可以把 Python 代码做成一个独立的服务(如 HTTP API、gRPC、ZeroMQ、共享内存、管道等),C++ 通过 IPC 调用。

例如:

复制代码
Python 启动一个 Flask/FastAPI 服务
C++ 用 libcurl 发送 HTTP 请求调用该服务

✅ 优点:解耦、跨语言、稳定
❌ 缺点:有网络开销、部署复杂度略高

方法四:将 Python 编译为 共享库(较难)

有一些工具尝试将 Python 编译成原生二进制(如 Cython、Nuitka、Shiv、PyOxidizer),但:

复制代码
Nuitka 可以将 Python 编译成 C++ 扩展模块(.so / .dll),但这些模块仍是供 Python 调用的,不是直接供 C++ 调用。
目前没有成熟方案能将任意 Python 代码直接编译成标准 C++ 可链接的 .so 库(像 C 函数那样被 extern "C" 调用)。

所以这条路通常不可行,除非你用 Cython 重写部分代码为 .pyx 并导出 C 接口。

实用建议:

场景 推荐方案
C++ 需频繁调用少量 Python 脚本 使用 Python/C API 嵌入解释器
Python 逻辑复杂、需长期运行 将 Python 做成 微服务,C++ 通过网络调用
性能敏感、低延迟 重写关键部分为 C++,用 pybind11 让 Python 调用 C++(反向)
不想依赖 Python 运行时 考虑用 Cython 重写并导出 C 接口

补充:构建注意事项

复制代码
C++ 项目需链接 Python 开发库(如 Ubuntu 上 sudo apt install python3-dev)
注意 Python 版本匹配(3.8/3.9/3.10...)
多线程环境下需注意 GIL(全局解释器锁)
相关推荐
2501_941870568 小时前
面向微服务熔断与流量削峰策略的互联网系统稳定性设计与多语言工程实践分享
开发语言·python
HABuo8 小时前
【Linux进程(四)】进程切换&环境变量深入剖析
linux·运维·服务器·c语言·c++·ubuntu·centos
工口发动机8 小时前
ABC440DEF简要题解
c++·算法
带土18 小时前
4. C++ static关键字
开发语言·c++
橘颂TA8 小时前
【Linux】死锁四条件的底层逻辑:从锁冲突到 STL 组件的线程安全实践(Ⅵ)
linux·运维·服务器·c++·死锁
C++ 老炮儿的技术栈8 小时前
什么是通信规约
开发语言·数据结构·c++·windows·算法·安全·链表
GIS之路8 小时前
GDAL 实现矢量裁剪
前端·python·信息可视化
IT=>小脑虎9 小时前
Python零基础衔接进阶知识点【详解版】
开发语言·人工智能·python
智航GIS9 小时前
10.6 Scrapy:Python 网页爬取框架
python·scrapy·信息可视化