QT C++调用Python模块捕获异常
在 C++ 中使用 Qt 调用 Python 脚本时,如果 Python 脚本在运行时抛出错误,可以捕获这些错误并在 Qt 中打印错误信息。为此,可以使用 PyErr_Print() 来打印错误信息,或者通过 PyErr_Fetch() 和 PyErr_NormalizeException() 来获取详细的错误信息并在 Qt 中处理。
示例代码
以下是一个示例代码,展示如何在 C++ 中使用 Qt 调用 Python 模块,并捕获和打印 Python 中的错误信息。
C++ Code
#include <Python.h>
#include <iostream>
#include <QString>
#include <QApplication>
#include <QLabel>
void executePythonFunction() {
Py_Initialize();
// Import the Python module
PyObject* moduleName = PyUnicode_DecodeFSDefault("my_module");
PyObject* module = PyImport_Import(moduleName);
Py_DECREF(moduleName);
if (module != nullptr) {
// Get the function from the module
PyObject* function = PyObject_GetAttrString(module, "my_function");
if (function && PyCallable_Check(function)) {
// Call the function
PyObject* result = PyObject_CallObject(function, nullptr);
if (result == nullptr) {
// Error occurred, print error information
PyErr_Print();
// Alternatively, fetch and handle the error manually
PyObject *ptype, *pvalue, *ptraceback;
PyErr_Fetch(&ptype, &pvalue, &ptraceback);
PyErr_NormalizeException(&ptype, &pvalue, &ptraceback);
// Print error type
if (ptype != nullptr) {
PyObject* str_exc_type = PyObject_Repr(ptype);
const char* err_type = PyUnicode_AsUTF8(str_exc_type);
std::cerr << "Error type: " << err_type << std::endl;
Py_XDECREF(str_exc_type);
}
// Print error value
if (pvalue != nullptr) {
PyObject* str_exc_value = PyObject_Repr(pvalue);
const char* err_value = PyUnicode_AsUTF8(str_exc_value);
std::cerr << "Error value: " << err_value << std::endl;
Py_XDECREF(str_exc_value);
}
// Print traceback
if (ptraceback != nullptr) {
PyObject* traceback_module = PyImport_ImportModule("traceback");
PyObject* format_tb_func = PyObject_GetAttrString(traceback_module, "format_exception");
PyObject* traceback_list = PyObject_CallFunctionObjArgs(format_tb_func, ptype, pvalue, ptraceback, nullptr);
PyObject* traceback_str = PyUnicode_Join(PyUnicode_FromString(""), traceback_list);
const char* tb = PyUnicode_AsUTF8(traceback_str);
std::cerr << "Traceback: " << std::endl << tb << std::endl;
Py_XDECREF(traceback_module);
Py_XDECREF(format_tb_func);
Py_XDECREF(traceback_list);
Py_XDECREF(traceback_str);
}
// Clear error indicator
PyErr_Clear();
} else {
// Handle result if needed
Py_DECREF(result);
}
Py_XDECREF(function);
} else {
PyErr_Print();
}
Py_XDECREF(module);
} else {
PyErr_Print();
}
Py_Finalize();
}
int main(int argc, char *argv[]) {
QApplication app(argc, argv);
// Call the Python function
executePythonFunction();
QLabel label("Check the console for Python error messages.");
label.show();
return app.exec();
}
Python 代码(my_module.py)
def my_function():
# Intentionally raise an error for demonstration
raise ValueError("This is a test error")
代码分析
初始化和导入模块:
使用 Py_Initialize() 初始化 Python 解释器。
使用 PyUnicode_DecodeFSDefault 和 PyImport_Import 导入 Python 模块 my_module。
获取和调用函数:
使用 PyObject_GetAttrString 获取模块中的函数 my_function。
使用 PyObject_CallObject 调用函数。
错误处理:
使用 PyErr_Print() 打印错误信息到标准错误。
或者,使用 PyErr_Fetch 和 PyErr_NormalizeException 获取详细的错误信息,并打印错误类型、错误值和堆栈跟踪。
显示错误信息:
使用标准输出流(std::cerr)在控制台中打印错误信息。
更通用情况
通常,Python 函数在执行过程中可能会遇到各种错误(例如零除错误、文件不存在错误等)。
如果没有主动 raise 异常,可以使用 PyErr_Occurred() 来检查是否有错误发生,然后使用 PyErr_Fetch() 获取详细的错误信息。
C++ 代码
#include <Python.h>
#include <iostream>
#include <QString>
#include <QApplication>
#include <QLabel>
void executePythonFunction() {
Py_Initialize();
// Import the Python module
PyObject* moduleName = PyUnicode_DecodeFSDefault("my_module");
PyObject* module = PyImport_Import(moduleName);
Py_DECREF(moduleName);
if (module != nullptr) {
// Get the function from the module
PyObject* function = PyObject_GetAttrString(module, "my_function");
if (function && PyCallable_Check(function)) {
// Call the function
PyObject* result = PyObject_CallObject(function, nullptr);
if (result == nullptr) {
// Error occurred, print error information
PyErr_Print();
// Alternatively, fetch and handle the error manually
PyObject *ptype, *pvalue, *ptraceback;
PyErr_Fetch(&ptype, &pvalue, &ptraceback);
PyErr_NormalizeException(&ptype, &pvalue, &ptraceback);
// Print error type
if (ptype != nullptr) {
PyObject* str_exc_type = PyObject_Repr(ptype);
const char* err_type = PyUnicode_AsUTF8(str_exc_type);
std::cerr << "Error type: " << err_type << std::endl;
Py_XDECREF(str_exc_type);
}
// Print error value
if (pvalue != nullptr) {
PyObject* str_exc_value = PyObject_Repr(pvalue);
const char* err_value = PyUnicode_AsUTF8(str_exc_value);
std::cerr << "Error value: " << err_value << std::endl;
Py_XDECREF(str_exc_value);
}
// Print traceback
if (ptraceback != nullptr) {
PyObject* traceback_module = PyImport_ImportModule("traceback");
PyObject* format_tb_func = PyObject_GetAttrString(traceback_module, "format_exception");
PyObject* traceback_list = PyObject_CallFunctionObjArgs(format_tb_func, ptype, pvalue, ptraceback, nullptr);
PyObject* traceback_str = PyUnicode_Join(PyUnicode_FromString(""), traceback_list);
const char* tb = PyUnicode_AsUTF8(traceback_str);
std::cerr << "Traceback: " << std::endl << tb << std::endl;
Py_XDECREF(traceback_module);
Py_XDECREF(format_tb_func);
Py_XDECREF(traceback_list);
Py_XDECREF(traceback_str);
}
// Clear error indicator
PyErr_Clear();
} else {
// Handle result if needed
Py_DECREF(result);
}
Py_XDECREF(function);
} else {
PyErr_Print();
}
Py_XDECREF(module);
} else {
PyErr_Print();
}
Py_Finalize();
}
int main(int argc, char *argv[]) {
QApplication app(argc, argv);
// Call the Python function
executePythonFunction();
QLabel label("Check the console for Python error messages.");
label.show();
return app.exec();
}
Python 代码(my_module.py)
def my_function():
x = 1 / 0 # This will raise a ZeroDivisionError
- PyObject_CallObject(function, nullptr) 调用 Python 函数 my_function。如果在执行过程中发生任何错误,result 将为 nullptr。
检查和处理错误: - 使用 PyErr_Print() 打印错误信息。
- 使用 PyErr_Fetch() 和 PyErr_NormalizeException() 获取详细的错误信息,并打印错误类型、错误值和堆栈跟踪。