前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >在 C++ 中捕获 Python 异常

在 C++ 中捕获 Python 异常

原创
作者头像
华科云商小徐
发布2024-02-05 10:15:48
2700
发布2024-02-05 10:15:48
举报
文章被收录于专栏:小徐学爬虫

在 C++ 中捕获 Python 异常的原理涉及到 Python C API 的使用和异常处理机制。下面简要介绍捕获 Python 异常的原理:Python C API 允许 C++ 代码与 Python 解释器进行交互,从而可以在 C++ 中调用 Python 函数、获取 Python 对象、捕获 Python 异常等操作。所以说能都捕获异常并做提示,针对后期代码优化有很大的帮助,下面就看看具体的解决方案吧。

1、问题背景

在开发一个服务器-客户端应用时,客户端会调用服务器的 API,该 API 提供了用于用户输入的 Python 接口。这意味着客户端接口和服务器接口是用 Python 编写的,而套接字代码是用 C++ 编写的。

在服务器端,我有一个 C++ 类的 Test,我们用 SWIG 的管理机制在 Python 中继承 Test,命名为 TestPython。我还定义一个 C++ 中的异常类 MyException。现在,TestPython 类的一个函数从 Python 代码中抛出了 MyException()。

我希望在 C++ 代码中使用 SWIG 来处理从 Python 中抛出的异常。因此,我想知道应该在 *.i(接口)文件中写什么来处理这种情况。

2、解决方案

为了实现这个功能,您需要编写一个 %feature("director:except"),它可以处理 Python 异常并将其重新抛出为 C++ 异常。以下是一个简单但完整的示例:

头文件 example.h

代码语言:javascript
复制
#include <iostream>
#include <exception>
​
class MyException : public std::exception {
};
​
class AnotherException : public std::exception {
};
​
class Callback {
public:
        virtual ~Callback() { std::cout << "~Callback()" << std:: endl; }
        virtual void run() { std::cout << "Callback::run()" << std::endl; }
};
​
inline void call(Callback *callback) { if (callback) callback->run(); }

Python 代码

代码语言:javascript
复制
import example 
​
class PyCallback(example.Callback):
    def __init__(self):
        example.Callback.__init__(self)
    def run(self):
        print("PyCallback.run()")
        raise example.MyException()
​
callback = PyCallback()
example.call(callback)

SWIG 接口文件

代码语言:javascript
复制
%module(directors="1") example
%{
#include "example.h"
%}
​
%include "std_string.i"
%include "std_except.i"
%include "pyabc.i"
​
// Python requires that anything we raise inherits from this
%pythonabc(MyException, Exception);
​
%feature("director:except") {
    PyObject *etype = $error;
    if (etype != NULL) {
      PyObject *obj, *trace;
      PyErr_Fetch(&etype, &obj, &trace);
      Py_DecRef(etype);
      Py_DecRef(trace);
      // Not too sure if I need to call Py_DecRef for obj
​
      void *ptr;
      int res = SWIG_ConvertPtr(obj, &ptr, SWIGTYPE_p_MyException, 0);
      if (SWIG_IsOK(res) && ptr) {
        MyException *e = reinterpret_cast< MyException * >(ptr);
        // Throw by pointer (Yucky!)
        throw e;
      }
​
      res = SWIG_ConvertPtr(obj, &ptr, SWIGTYPE_p_AnotherException, 0);
      if (SWIG_IsOK(res) && ptr) {
        AnotherException *e = reinterpret_cast< AnotherException * >(ptr);
        throw e; 
      }
​
      throw Swig::DirectorMethodException();
    }
}
​
%feature("director") Callback;
%include "example.h"

代码会处理来自管理函数的错误,检查它是否是我们 MyException 实例之一,如果是,则重新抛出指针。如果您有多种类型的异常被抛出,那么您可能需要先使用 PyErr_ExceptionMatches 来计算出它的类型。

通过调用 SWIG 使用 -py3 参数,我们就可以让这个示例工作(否则 %pythonabc 不起作用)。这又意味着我们必须升级到 SWIG 2.0,因为我安装的 Python 3.2 从 C-API 中删除了一些 SWIG 1.3.40 调用的已弃用的函数。

在调用 Python 函数后,可以使用 PyErr_Occurred() 检查是否发生了异常,并使用 PyErr_Print() 打印异常信息。在实际应用中,你可能需要根据你的需求进行更详细的异常处理。

此外,要确保在 C++ 代码中正确处理 Python 的引用计数,避免内存泄漏,可以使用 Py_XDECREF 来递减引用计数。以上就是今天的全部内容,如果有更好的学习技巧或者需要解答的地方,记得评论区留言讨论。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
相关产品与服务
云服务器
云服务器(Cloud Virtual Machine,CVM)提供安全可靠的弹性计算服务。 您可以实时扩展或缩减计算资源,适应变化的业务需求,并只需按实际使用的资源计费。使用 CVM 可以极大降低您的软硬件采购成本,简化 IT 运维工作。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档