Python与C/C++代码的集成与调用方法

文章目录

  • 1. 使用ctypes调用C/C++代码
  • 1.1 编写C/C++代码
  • 1.2 编译C/C++代码
  • 1.3 在Python中调用C/C++函数
  • 2. 使用pybind11调用C/C++代码
  • 2.1 编写C/C++代码
  • 2.2 编译C/C++代码
  • 2.3 在Python中调用C/C++函数
  • 3. c++调用python代码
  • 4. 总结
  • 在现代软件开发中,Python因其简洁易用和丰富的生态系统而广受欢迎。然而,Python在性能上有时无法满足需求,尤其是在计算密集型任务中。这时,调用C/C++代码成为提升性能的有效手段。本文将介绍如何通过ctypespybind11两种方式在Python中调用C/C++代码,并分析其优缺点。

    1. 使用ctypes调用C/C++代码

    1.1 编写C/C++代码

    首先,我们编写一个简单的C++函数,并将其编译为共享库(.so文件)。

    // mylib.cpp
    #include <iostream>
    extern "C" {
        int add(int a, int b) {
            std::cout << "add called" << std::endl;
            return a + b;
        }
    }
    

    1.2 编译C/C++代码

    使用以下命令将C++代码编译为共享库:

    g++ -shared -o libmylib.so -fPIC mylib.cpp
    
  • -shared:生成共享库。
  • -o libmylib.so:指定输出文件名为libmylib.so
  • -fPIC:生成位置无关代码(Position Independent Code),这是共享库所必需的。
  • 1.3 在Python中调用C/C++函数

    使用ctypes库加载共享库并调用C++函数:

    import ctypes
    import os
    
    # 加载共享库
    lib = ctypes.CDLL(os.path.abspath("libmylib.so"))
    
    # 调用 C++ 函数
    result = lib.add(3, 4)  # add called
    print(f"Result: {result}")  # 输出: Result: 7
    

    2. 使用pybind11调用C/C++代码

    需要 pip install pybind11
    pybind11 的名字中的 11 表示它需要 C++11 或更高版本 的支持

    2.1 编写C/C++代码

    pybind11是一个轻量级的C++库,用于将C++代码暴露给Python。我们编写一个简单的C++函数,并使用pybind11将其绑定到Python。

    // mylib_pybind.cpp
    #include <pybind11/pybind11.h>
    #include <iostream>
    
    int add(int a, int b) {
        std::cout << "add called from pybind" << std::endl;
        return a + b;
    }
    
    PYBIND11_MODULE(mylib_pybind, m) {
        m.def("add", &add, "A function that adds two numbers");
    }
    

    2.2 编译C/C++代码

    使用以下命令将C++代码编译为Python模块:

    c++ -O3 -Wall -shared -std=c++11 -fPIC $(python3 -m pybind11 --includes) mylib_pybind.cpp -o mylib_pybind$(python3-config --extension-suffix)
    

    生成了 mylib_pybind.cpython-311-x86_64-linux-gnu.so 文件

  • -O3:优化级别为3,生成高度优化的代码。
  • -Wall:启用所有警告。
  • -shared:生成共享库。
  • -std=c++11:使用C++11标准。
  • -fPIC:生成位置无关代码。
  • $(python3 -m pybind11 --includes):获取pybind11的头文件路径。
  • -o mylib_pybind$(python3-config --extension-suffix):指定输出文件名,并使用Python的扩展名后缀。
  • 2.3 在Python中调用C/C++函数

    import mylib_pybind as mylib
    
    result = mylib.add(3, 4)  # add called from pybind
    print(f"Result: {result}")  # 输出: Result: 7
    

    3. c++调用python代码

    # example.py
    def add(a, b):
        return a + b
    
    #include <pybind11/embed.h>  // 嵌入 Python 解释器
    #include <iostream>
    
    namespace py = pybind11;
    
    int main() {
        // 启动 Python 解释器
        py::scoped_interpreter guard{};
    
        // 导入 Python 模块
        py::module_ example = py::module_::import("example");
    
        // 调用 Python 函数
        py::object result = example.attr("add")(3, 4);
        std::cout << "Result: " << result.cast<int>() << std::endl;  // 输出: Result: 7
    
        return 0;
    }
    
    g++ -o call_py call_py.cpp -I/opt/conda/envs/ai/include/python3.10/ $(python3 -m pybind11 --includes) -L/opt/conda/envs/ai/lib -lpython3.10
    
    echo 'export LD_LIBRARY_PATH=/opt/conda/envs/ai/lib:$LD_LIBRARY_PATH' >> ~/.bashrc
    source ~/.bashrc
    

    执行 ./call_py

    4. 总结

    Python调用C/C++代码是一种常见的性能优化手段,适用于需要高性能计算的场景。
    ctypes适合简单的函数调用,而pybind11则更适合复杂的C++代码集成。
    尽管调用C/C++代码可以显著提升性能,但也带来了额外的复杂性和开发成本,因此在决定使用时应权衡利弊。

    作者:Michael阿明

    物联沃分享整理
    物联沃-IOTWORD物联网 » Python与C/C++代码的集成与调用方法

    发表回复