在C ++中捕获Python异常 [英] Catching a Python exception in C++

查看:149
本文介绍了在C ++中捕获Python异常的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在开发一个服务器 - 客户端应用程序,其中客户端调用服务器的API,为用户输入提供一个Python接口。这意味着客户端接口和服务器接口是用Python编写的,而套接字代码是用C ++编写的。



在服务器端: -



我有一个类, Test ,在C ++中,这个类继承于Python命名为TestPython,使用 SWIG
我也有一个异常类MyException在C + +。



现在一个TestPython类的函数类throws MyException()从Python代码。



我想使用SWIG在C ++代码中处理Python抛出的异常。



以下是代码段:



C ++代码 -

  class MyException 
{
public:
string errMsg;
MyException();
MyException(string);
〜MyException();
};

class Test
{
int value;
public:
void TestException(int val);
Test(int);
};

Python代码 -

  class TestPython(Test):
def __init __(self):
Test .__ init __(self)

def TestException(self,val):
if val> 20:
throw MyException(MyException:Value Exceeded !!!)
else:
printValue passed =,val
pre>

现在,如果 TestException()函数被调用,它应该抛出 MyException 。我想在我的C ++代码中处理这个 MyException()异常。



任何人都可以建议我如何做那么,我的意思是我应该写在我的* .i(接口)文件来处理这个。



上面的 TestException c $ c>由客户端调用,所以我必须通知客户端如果任何异常被服务器抛出。

解决方案

要做到这一点你基本上需要写一个%特性(director:except)可以处理一个Python异常并重新抛出它作为一个C ++ 。这是一个小但完整的例子:



假设我们有以下头文件,我们希望换行:

  #include< iostream> 
#include< exception>

class MyException:public std :: exception {
};

class AnotherException:public std :: exception {
};

类回调{
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代码:

  import example 

class PyCallback(example.Callback):
def __init __(self):
example.Callback .__ init __ self)
def run(self):
print(PyCallback.run())
raise example.MyException()

callback = PyCallback b $ b example.call(callback)

我们可以定义以下SWIG接口文件:

 %module(directors =1)example 
%{
#includeexample.h
%}

%includestd_string.i
%includestd_except.i
%includepyabc.i

/ / Python要求我们继承的任何东西从这个
%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);
//不太确定如果我需要调用Py_DecRef obj

void * ptr;
int res = SWIG_ConvertPtr(obj,& ptr,SWIGTYPE_p_MyException,0);
if(SWIG_IsOK(res)&& ptr){
MyException * e = reinterpret_cast< MyException *>(ptr);
//通过指针(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();
}
}

%特性(director)回调;
%includeexample.h

其中处理来自董事的错误看看它是否是我们的 MyException 实例之一,然后重新抛出指针,如果是的话。如果您抛出了多种类型的异常,则可能需要使用 <$ c



我们可以通过值或引用使用:

/ p>

  //通过值抛出(复制之后)
MyException temp = * e;
if(SWIG_IsNewObj(res))
delete e;
throw temp;

,但请注意,如果您投入 $ c> MyException 在Python中,这会违反对象切片问题



我不太确定代码是否100%正确 - 特别是我认为引用计数是正确的,但我可能是错误的。



注意:为了使此示例工作(%pythonabc 我不得不调用SWIG与 -py3 。这反过来意味着我不得不升级到SWIG 2.0,因为我安装的Python 3.2的副本已经从SWIG 1.3.40调用的C-API中删除了一些已弃用的函数。


I am developing a server-client application in which the client calls a server's API which gives a Python interface for user input. It means the client interface and server interface is written in Python whereas the socket code is in C++.

On the server side:-

I have a class, Test, in C++ and this class is inherited in Python named TestPython using director feature of SWIG. Also I have an exception class MyException in C++.

Now a function of TestPython class throws MyException() from Python code.

I want to handle exception thrown from Python in C++ code using SWIG.

Below is code snippet:

C++ Code-

class MyException
{
   public:
     string errMsg;
     MyException();
     MyException(string);
     ~MyException();
};

class Test
{
    int value;
    public:
      void TestException(int val);
      Test(int);
};

Python Code -

class TestPython(Test):
   def __init__(self):
     Test.__init__(self)

   def TestException(self,val):
     if val > 20:   
       throw MyException("MyException : Value Exceeded !!!")   
     else:    
       print "Value passed = ",val

Now, if the TestException() function is called, it should throw MyException. I want to handle this MyException() exception in my C++ code.

So can anyone suggest my how to do that, I mean what should I write in my *.i(interface) file to handle this.

The above TestException() written in Python is called by the client, so I have to notify the client if any exception is thrown by the server.

解决方案

To do this you basically need to write a %feature("director:except") that can handle a Python exception and re-throw it as a C++ one. Here's a small but complete example:

Suppose we have the following header file we wish to wrap:

#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(); }

And this Python code that uses it:

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)

We can define the following SWIG interface file:

%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"

Which handles an error from a director call, looks to see if it was one of our MyException instances and then re-throws the pointer if it was. If you have multiple types of exception being thrown then you will probably need to use PyErr_ExceptionMatches to work out what type it is first.

We could throw also by value or reference using:

  // Throw by value (after a copy!)
  MyException temp = *e;
  if (SWIG_IsNewObj(res)) 
    delete e;
  throw temp;

instead, but note that if you threw a subclass of MyException in Python this would fall foul of the object slicing problem.

I'm not quite sure if the code is 100% correct - in particular I think the reference counting is correct, but I could be wrong.

Note: In order to make this example work (%pythonabc wouldn't work otherwise) I had to call SWIG with -py3. This in turn meant I had to upgrade to SWIG 2.0, because my installed copy of Python 3.2 had removed some deprecated functions from the C-API that SWIG 1.3.40 called.

这篇关于在C ++中捕获Python异常的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆