Python与C/C++代码的集成与调用方法
文章目录
在现代软件开发中,Python因其简洁易用和丰富的生态系统而广受欢迎。然而,Python在性能上有时无法满足需求,尤其是在计算密集型任务中。这时,调用C/C++代码成为提升性能的有效手段。本文将介绍如何通过ctypes
和pybind11
两种方式在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阿明