C++程序嵌入python脚本调试
C++程序嵌入python脚本调试
- 介绍
- 调试方法
- 方法一:使用 `pydevd-pycharm` 进行远程调试(推荐)
- 方法二:使用 `pdb` 进行交互式调试
- 方法三:最朴素的打印日志
- 总结与建议
介绍
在 Qt/C++ 应用程序中内嵌 Python 解释器来执行脚本是一种非常常见的架构。虽然 Python 脚本没有独立的进程,但它仍然在主体应用程序的进程内运行,本文提供了几种有效的调试方法。
调试的核心思路是:让一个外部的、功能强大的调试器(如 PyCharm、VS Code 的调试器)连接到内嵌在您主体软件中的 Python 解释器会话。这个过程通常被称为“远程调试”(Remote Debugging),尽管“连接”发生在同一台机器甚至同一个进程内。
Github项目:embed_python
Bilibili视频演示
调试方法
方法一:使用 pydevd-pycharm
进行远程调试(推荐)
这是最强大、最接近现代 IDE 调试体验的方法。PyCharm/VSCode 等 IDE 的调试器本质是一个调试服务器,而 pydevd
是一个调试客户端库。您需要在您的 Python 脚本中“植入”这个客户端,让它去连接 IDE 的调试服务器。
步骤:
-
安装调试器包:
根据您使用的 IDE 安装对应的包:-
PyCharm 用户:安装
pydevd-pycharm
(通常与您的 PyCharm 版本绑定,最好使用与 IDE 相同的版本)。pip install pydevd-pycharm~=232.10203.10 # 请替换为您的 PyCharm 版本号
-
VS Code 用户:安装
debugpy
。pip install debugpy
-
-
在您的 Python 脚本中插入调试代码:
在您需要开始调试的脚本最开头,添加以下代码片段。对于 PyCharm/pydevd:
import pydevd_pycharm # 连接到本机(127.0.0.1)的 5678 端口(PyCharm 默认监听端口) pydevd_pycharm.settrace('127.0.0.1', port=5678, stdoutToServer=True, stderrToServer=True)
对于 VS Code/debugpy:
import debugpy # 允许其他进程连接(0.0.0.0)并监听 5678 端口 debugpy.listen(('0.0.0.0', 5678)) # 等待调试器附加 debugpy.wait_for_client() # 设置断点 debugpy.breakpoint()
-
在 IDE 中配置调试服务器:
- PyCharm:
- 进入
Run -> Edit Configurations...
。 - 点击
+
号,选择Python Debug Server
。 - 给它起个名字(如 “Embedded Python”),配置端口(默认为 5678,与脚本中的一致)。
- 点击
OK
保存。 - 点击工具栏上的调试按钮(绿色的虫子)启动这个调试服务器,让它开始监听连接。
- 进入
- VS Code:
- 切换到“运行和调试”视图。
- 点击
create a launch.json file
或编辑现有配置。 - 选择
Python -> Remote Attach
。 - 配置
"host"
为"localhost"
,"port"
为5678
(与脚本中一致)。 - 保存
launch.json
。
- PyCharm:
-
开始调试:
- 首先在您的 IDE 中启动调试服务器(点击“调试”按钮)。
- 然后,在您的 Qt 主体软件中触发执行那个插入了调试代码的 Python 脚本。
- 当脚本执行到
settrace()
或wait_for_client()
时,它会暂停执行,并向 IDE 的调试服务器发起连接。 - 连接成功后,IDE 的调试界面就会激活,您可以像调试普通 Python 程序一样使用所有的调试功能:设置断点、单步执行、查看变量、观察堆栈等。
方法二:使用 pdb
进行交互式调试
如果环境受限无法安装第三方库,可以使用 Python 标准库自带的 pdb
。不过,由于您的 Python 运行在 Qt 应用的上下文中,直接使用 pdb
会占用主进程的标准输入输出,可能导致界面卡死或无响应。但可以尝试重定向输入输出。
在您的脚本中需要调试的地方插入:
import pdb; pdb.set_trace()
当执行到这一行时,解释器会暂停并尝试进入交互式调试。您需要确保主体应用程序有一个可以输入命令的控制台窗口(例如,在启动 Qt 应用时带有一个终端),否则您将无法与 pdb
交互。
这种方法比较原始,体验远不如方法一,仅作为备用方案。
方法三:最朴素的打印日志
这不算严格的调试,但永远是快速排查问题的有效手段。
import logging
logging.basicConfig(level=logging.DEBUG, format='%(asctime)s - %(levelname)s - %(message)s')
logger = logging.getLogger(__name__)# 在代码中需要的地方打日志
logger.debug("变量 x 的值是: %s", x)
您可以将日志输出到文件,以便在程序运行时持续观察。
总结与建议
方法 | 优点 | 缺点 | 适用场景 |
---|---|---|---|
pydevd /debugpy | 功能强大,支持图形化IDE断点、单步、变量监视,体验最佳 | 需要安装额外包,配置稍复杂 | 强烈推荐,适用于大多数开发调试场景 |
pdb | 无需额外安装,Python 自带 | 交互不便,易导致GUI卡死,功能较弱 | 快速、简单的故障排查,且环境受限时 |
打印日志 | 简单,无需调试配置 | 需要修改代码,效率低,无法交互 | 任何场景的辅助排查 |