游乐游手机版
首页/编程语言/文章详情

Boost.Python嵌入教程:从C/C++调用Python代码

时间:2026-06-22 10:23
使用Boost Python可将Python解释器嵌入C++程序,并辅以Python CAPI弥补不足。构建时链接Boost Python和Python库,通过handle和object类自动管理引用计数,避免内存泄漏。提供eval、exec、exec_file函数运行Python代码,支持导入模块。异常时抛出error_already_set,可用PyEr

使用解释器

看到这里,你应该已经掌握了如何用 Boost.Python 从 Python 调用 C++ 代码。但现实总要更复杂一些——有时候你需要反过来:从 C++ 端去调用 Python 代码。这就需要你把 Python 解释器“嵌入”到 C++ 程序中。

目前,Boost.Python 并没有把嵌入所需的一切功能都打包好,所以你还需要借助 Python/C API 来补上那些缺口。不过,Boost.Python 已经让嵌入这件事变得容易了不少,而且可以期待的是,在后续版本中,你甚至完全不需要碰 Python/C API。这一点值得持续关注。

构建嵌入式程序

想要把 Python 嵌入到你的程序里,链接时需要连上 Boost.Python 和 Python 自身的运行时库。

Boost.Python 的库有两个变体,都放在 Boost 的 /libs/python/build/bin-stage 子目录下。在 Windows 上,发布版叫 boost_python.lib,调试版叫 boost_python_debug.lib。如果你找不到对应库,那大概率是还没构建 Boost.Python。

Python 的库则在 Python 目录下的 /libs 子目录中。Windows 上它叫 pythonXY.lib,其中 XY 对应你的 Python 主版本号。

另外,记得把 Python 的 /include 子目录加到包含路径里。

用 Jamfile 来组织这一切的话,大致是这样:

projectroot c:projectsembedded_program ; # location of the program
# bring in the rules for python
SEARCH on python.jam = $(BOOST_BUILD_PATH) ;
include python.jam ;
exe embedded_program # name of the executable
: # sources
embedded_program.cpp
: # requirements
boost_python
c:boostlibspython$(PYTHON_PROPERTIES)
$(PYTHON_LIB_PATH)
$(PYTHON_EMBEDDED_LIBRARY) ;

入门

能构建工程是好事,但还缺真正要运行的东西。想要把 Python 解释器嵌入到你的 C++ 程序里,需要按顺序完成四个步骤:

  1. #include
  2. 调用 Py_Initialize() 启动解释器,并创建 __main__ 模块。
  3. 调用其他 Python C API 例程来使用解释器。
  4. (注意:此时还不能调用 Py_Finalize() 来停止解释器。这个问题可能会在未来的 boost.python 版本中得到解决。)

现在我们可以把解释器嵌入到程序里了,接下来看看怎么用它。

使用解释器

你可能已经知道,Python 中的对象是引用计数的。Python C API 的 PyObject 自然也沿用这一机制。但区别在于:Python 内部引用计数是全自动的,而 Python C API 却要求你手动处理。这很麻烦,而且一旦碰上 C++ 异常,手动管理更是容易出问题。好在 Boost.Python 提供了 handleobject 类模板,帮我们把这一过程自动化了。

运行 Python 代码

Boost.Python 提供了三个函数,用来从 C++ 端运行 Python 代码:

object eval(str expression, object globals = object(), object locals = object())
object exec(str code, object globals = object(), object locals = object())
object exec_file(str filename, object globals = object(), object locals = object())

eval 计算给定的表达式并返回结果值;exec 执行一段代码(通常是一组语句),它不返回值(但你可以通过字典拿到结果);exec_file 则直接执行一个文件中的代码。

globalslocals 参数都是 Python 字典,用于指定代码运行时的全局与局部变量上下文。在大多数场景下,直接拿 __main__ 模块的命名空间字典来当这两个参数就足够了。

此外,Boost.Python 还提供了导入模块的功能:

object import(str name)

它会导入指定的 Python 模块(必要时会将其加载到当前进程中),然后返回该模块对象。

看个例子:导入 __main__ 模块,并在它的命名空间里执行一段 Python 代码。

object main_module = import("__main__");
object main_namespace = main_module.attr("__dict__");
object ignored = exec("hello = file('hello.txt', 'w')\n"
    "hello.write('Hello world!')\n"
    "hello.close()",
    main_namespace);

这段代码会在当前目录创建一个叫 hello.txt 的文件,里面写着那句编程圈无人不晓的问候语。

操纵 Python 对象

很多时候我们需要一个类来直接操作 Python 对象。其实上一节已经见过了——那个名字很直白的 object 类(以及它的派生类)。它们可以用 handle 来构造。下面这个例子应该能让你更清楚:

object main_module = import("__main__");
object main_namespace = main_module.attr("__dict__");
object ignored = exec("result = 5 ** 2", main_namespace);
int five_squared = extract(main_namespace["result"]);

这里先获得 __main__ 模块的命名空间字典,然后把 5 ** 2 的结果赋给变量 result,最后从字典中读出并提取成整数。当然,更简单的做法是用 eval

object result = eval("5 ** 2");
int five_squared = extract(result);

异常处理

如果在执行 Python 表达式时发生了异常,Boost.Python 会抛出 error_already_set 异常:

try
{
    object result = eval("5/0");
    // 执行永远不会到这一行:
    int five_divided_by_zero = extract(result);
}
catch(error_already_set const &)
{
    // 用某种方式处理异常
}

error_already_set 异常类本身不包含任何信息。想了解发生了什么 Python 异常,你得在 catch 块里使用 Python C API 的异常处理函数。最简单的做法是调用 PyErr_Print() 把异常回显打印到控制台,或者比较异常类型:

catch(error_already_set const &)
{
    if (PyErr_ExceptionMatches(PyExc_ZeroDivisionError))
    {
        // 专门处理除零异常
    }
    else
    {
        // 把其他所有错误打印到 stderr
        PyErr_Print();
    }
}
来源:https://blog.csdn.net/xinqingwuji/article/details/89316266
上一篇使用Boost.Python库实现C++与Python相互调用的详细步骤与指南 下一篇Python变量基础概念与代码实战教程
本站内容用于信息整理与展示,如有侵权或内容问题请及时联系处理。

相关推荐

补充同频道和同主题内容,方便继续浏览更多相关内容。

同类最新

继续查看同栏目最近更新的文章。

更多
CentOS与Golang打包常见兼容性问题探讨
编程语言 · 2026-07-01

CentOS与Golang打包常见兼容性问题探讨

CentOS与Golang打包的兼容性问题集中在glibc版本不匹配、交叉编译环境变量错误、依赖库缺失及Go依赖管理不规范。可通过Docker容器编译、选择兼容Go版本、正确设置GOOS GOARCH环境变量、安装对应开发包及使用GoModules解决。

CentOS中Fortran与Python如何协同工作从入门到实战完整教程
编程语言 · 2026-07-01

CentOS中Fortran与Python如何协同工作从入门到实战完整教程

在CentOS中,Fortran与Python可通过f2py、SWIG、共享库调用或subprocess协同。f2py封装Fortran为Python模块,支持数组运算;共享库需手动对齐数据类型;系统调用适合独立计算。

CentOS中Golang打包优化方法
编程语言 · 2026-07-01

CentOS中Golang打包优化方法

在CentOS中优化Golang编译打包,可显著提升编译速度并减小二进制文件体积。关键技巧包括:设置环境变量、使用Go模块管理依赖、编译时添加-ldflags= "-s-w "去除调试信息、利用UPX工具压缩、运行strip清理符号表,以及优化cgo内C代码的编译选项。综合运用这些方法能有效优化最终程序。

在CentOS系统中cpustat与其他工具协同使用的完整方法
编程语言 · 2026-07-01

在CentOS系统中cpustat与其他工具协同使用的完整方法

cpustat作为sysstat包的CPU监控工具,可通过管道与grep等命令配合过滤数据,利用脚本自动记录带时间戳的日志,或结合图形工具查看,也可格式化输出后接入Zabbix、Grafana等Web监控系统,实现可视化与告警。

CentOS中readdir与其他Linux发行版的差异
编程语言 · 2026-07-01

CentOS中readdir与其他Linux发行版的差异

CentOS基于RHEL,与Ubuntu、Debian、Fedora在包管理器(yum dnfvsapt)、默认文件系统(XFSvsext4)等存在差异,但readdir等系统调用遵循POSIX标准,行为一致。