简介
python 是解释型语言, 语法写起来方便但执行速度较慢.
c++ 等编译语言速度最快, 但指针, 数组越界等 使用易犯错.
于是兼顾人的开发效率与执行效率, 有了这样的思想:
关键模块用C/C++ 写, 调用的时候使用 python 来调用, 即 extending python with c/c++.
这一设想被广泛地应用于各个解释型/ 托管 语言中. 如 java 可以有 native 方法来调用.
原理
python 目录的 include/ 目录下有相关头文件, 按照约定写一个wrapper, 就能与 python 解释器互通了.
包装下来代码量有点多, 因为不少代码是有规律的, 这意味着可以靠三方工具辅助, 如 pybind11.
还有个方案是 ctypes, python 自带的模块, 与 .so , .dll 交互. 见参考[5]
pybind11
几大优点:
- 可以优雅绑定 c++代码, 其他工具的教程以 C语言为主.
- 可以绑定 c++ 的类, 方便我们面向对象编程.
- 除了基本类型, stl的vector, map 也可以自动地与 python 的list, dict 等作参数自动转换.
从 PyBind11 生成的 Python 绑定(.pyd,.so)是一个完整的 Python 模块,可以直接导入和使用。意味着运行环境不需要安装 pybind11 的库依赖.
pip install pybind11
即可安装.
开发
- 业务逻辑.
- bind_module
类型选择
string 是万能的, 当 json 用, 可以嵌套很深.
numpy 对象. 见参考 [8,9].
编译
c++ -O3 -Wall -shared -std=c++11 -fPIC $(python3 -m pybind11 --includes) example.cpp -o example$(python3-config --extension-suffix)
注意内含两个 动态变量. 先执行括号内 shell 语句, 再将结果作替换, 再执行整个 c++ 编译语句.
$(python3 -m pybind11 --includes)
$(python3-config --extension-suffix)
(base) yichu@ubuntu:~$ echo $(python3 -m pybind11 --includes)
-I/home/yichu/anaconda3/include/python3.9 -I/home/yichu/anaconda3/lib/python3.9/site-packages/pybind11/include
(base) yichu@ubuntu:~$ echo $(python3-config --extension-suffix)
.cpython-39-x86_64-linux-gnu.so
gcc(c++) -I
选项 可以指定本次编译的头文件目录. 详见参考[6].
gcc(c++) -fPIC
选项表示按照 位置无关( Position-Independent Code) 方式编译, 多用于 .so 共享库编译.
tips
-
同一OS, 不同python版本下编译的 .so, 似乎并不通用. 报错为 找不到模块.
-
加载时报错 undefined symbol.
怀疑是 gcc 版本与系统库的版本差异.
numpy 支持
todo.