boost :: python导出自定义异常 [英] boost::python Export Custom Exception

查看:279
本文介绍了boost :: python导出自定义异常的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我目前正在使用Boost.Python编写Python的C ++扩展。此扩展中的函数可能会生成一个包含错误信息的异常(不仅仅是一个描述发生了什么事的人类可读的字符串)。我希望我可以导出这个异常到Python,所以我可以抓住它,并做一些额外的信息。



例如:

  import my_cpp_module 
try:
my_cpp_module.my_cpp_function()
除了my_cpp_module.MyCPPException,e:
print e。 my_extra_data

不幸的是Boost.Python似乎翻译了所有C ++异常(即 std :: exception )转换为 RuntimeError 。我意识到Boost.Python允许一个实现自定义异常翻译,但是,需要使用 PyErr_SetObject ,它需要一个 PyObject * (对于异常的类型)和 PyObject * (对于异常的值) - 我都不知道如何从我的Boost.Python类。也许有一种方法(这将是伟大的),我只是还没有发现。

解决方案

解决方案是创建一个自定义的C ++异常,你的异常类像任何正常的C ++类

  class MyCPPException:public std :: exception {...} 

诀窍是,所有boost :: python :: class_实例都持有对对象类型的引用, ()函数。你可以得到这个注册类与boost :: python像这样:

  class_< MyCPPException> myCPPExceptionClass(MyCPPException...); 
PyObject * myCPPExceptionType = myCPPExceptionClass.ptr();
register_exception_translator< MyCPPException>(& translateFunc);

最后,当您将C ++异常转换为Python异常时, / p>

  void translate(MyCPPException const& e)
{
PyErr_SetObject(myCPPExceptionType,boost :: python: :object(e).ptr());
}

这是一个完整的工作示例:

  #include< boost / python.hpp> 
#include< assert.h>
#include< iostream>

类MyCPPException:public std :: exception
{
private:
std :: string message;
std :: string extraData;
public:
MyCPPException(std :: string message,std :: string extraData)
{
this-> message = message;
this-> extraData = extraData;
}
const char * what()const throw()
{
return this-> message.c_str();
}
〜MyCPPException()throw()
{
}
std :: string getMessage()
{
return this-> ;信息;
}
std :: string getExtraData()
{
return this-> extraData;
}
};

void my_cpp_function(bool throwException)
{
std :: cout< 调用C ++函数。 << std :: endl;
if(throwException)
{
throw MyCPPException(根据请求抛出异常,
这是额外的数据。
}
}

PyObject * myCPPExceptionType = NULL;

void translateMyCPPException(MyCPPException const& e)
{
assert(myCPPExceptionType!
boost :: python :: object pythonExceptionInstance(e);
PyErr_SetObject(myCPPExceptionType,pythonExceptionInstance.ptr());
}

BOOST_PYTHON_MODULE(my_cpp_extension)
{
boost :: python :: class_< MyCPPException>
myCPPExceptionClass(MyCPPException,
boost :: python :: init< std :: string,std :: string>());
myCPPExceptionClass.add_property(message,& MyCPPException :: getMessage)
.add_property(extra_data,& MyCPPException :: getExtraData);
myCPPExceptionType = myCPPExceptionClass.ptr();
boost :: python :: register_exception_translator< MyCPPException>
(& translateMyCPPException);
boost :: python :: def(my_cpp_function,& my_cpp_function);
}

这是调用扩展的Python代码:



import my_cpp_extension
try:
my_cpp_extension.my_cpp_function(False)
print'这行应该没有异常应抛出。
except my_cpp_extension.MyCPPException,e:
print'Message:',e.message
print'Extra data:',e.extra_data

try:
my_cpp_extension.my_cpp_function(True)
print('这行不应该被作为一个异常应该是'+
'现在抛出'。

p >

I am currently writing a C++ extension for Python using Boost.Python. A function in this extension may generate an exception containing information about the error (beyond just a human-readable string describing what happened). I was hoping I could export this exception to Python so I could catch it and do something with the extra information.

For example:

import my_cpp_module
try:
    my_cpp_module.my_cpp_function()
except my_cpp_module.MyCPPException, e:
    print e.my_extra_data

Unfortunately Boost.Python seems to translate all C++ exceptions (that are subclasses of std::exception) into RuntimeError. I realize that Boost.Python allows one to implement custom exception translation however, one needs to use PyErr_SetObject which takes a PyObject* (for the exception's type) and a PyObject* (for the exception's value)--neither of which I know how to get from my Boost.Python classes. Perhaps there is a way (which would be great) that I simply have not found yet. Otherwise does anyone know how to export a custom C++ exception so that I may catch it in Python?

解决方案

The solution is to create your exception class like any normal C++ class

class MyCPPException : public std::exception {...}

The trick is that all boost::python::class_ instances hold a reference to the object's type which is accessible through their ptr() function. You can get this as you register the class with boost::python like so:

class_<MyCPPException> myCPPExceptionClass("MyCPPException"...);
PyObject *myCPPExceptionType=myCPPExceptionClass.ptr();
register_exception_translator<MyCPPException>(&translateFunc);

Finally, when you are translating the C++ exception to a Python exception, you do so as follows:

void translate(MyCPPException const &e)
{
    PyErr_SetObject(myCPPExceptionType, boost::python::object(e).ptr());
}

Here is a full working example:

#include <boost/python.hpp>
#include <assert.h>
#include <iostream>

class MyCPPException : public std::exception
{
private:
  std::string message;
  std::string extraData;
public:
  MyCPPException(std::string message, std::string extraData)
  {
    this->message = message;
    this->extraData = extraData;
  }
  const char *what() const throw()
  {
    return this->message.c_str();
  }
  ~MyCPPException() throw()
  {
  }
  std::string getMessage()
  {
    return this->message;
  }
  std::string getExtraData()
  {
    return this->extraData;
  }
};

void my_cpp_function(bool throwException)
{
  std::cout << "Called a C++ function." << std::endl;
  if (throwException)
    {
      throw MyCPPException("Throwing an exception as requested.",
               "This is the extra data.");
    }
}

PyObject *myCPPExceptionType = NULL;

void translateMyCPPException(MyCPPException const &e)
{
  assert(myCPPExceptionType != NULL);
  boost::python::object pythonExceptionInstance(e);
  PyErr_SetObject(myCPPExceptionType, pythonExceptionInstance.ptr());
}

BOOST_PYTHON_MODULE(my_cpp_extension)
{
  boost::python::class_<MyCPPException>
    myCPPExceptionClass("MyCPPException",
            boost::python::init<std::string, std::string>());
  myCPPExceptionClass.add_property("message", &MyCPPException::getMessage)
    .add_property("extra_data", &MyCPPException::getExtraData);
  myCPPExceptionType = myCPPExceptionClass.ptr();
  boost::python::register_exception_translator<MyCPPException>
    (&translateMyCPPException);
  boost::python::def("my_cpp_function", &my_cpp_function);
}

Here is the Python code that calls the extension:

import my_cpp_extension
try:
    my_cpp_extension.my_cpp_function(False)
    print 'This line should be reached as no exception should be thrown.'
except my_cpp_extension.MyCPPException, e:
    print 'Message:', e.message
    print 'Extra data:',e.extra_data

try:
    my_cpp_extension.my_cpp_function(True)
    print ('This line should not be reached as an exception should have been' +
       'thrown by now.')
except my_cpp_extension.MyCPPException, e:
    print 'Message:', e.message
    print 'Extra data:',e.extra_data

这篇关于boost :: python导出自定义异常的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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