在C ++中捕获Python异常 [英] Catching a Python exception in C++
问题描述
我正在开发一个服务器 - 客户端应用程序,其中客户端调用服务器的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):
pre>
def __init __(self):
Test .__ init __(self)
def TestException(self,val):
if val> 20:
throw MyException(MyException:Value Exceeded !!!)
else:
printValue passed =,val
现在,如果
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 throwMyException
. I want to handle thisMyException()
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 usePyErr_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屋!