2010-02-14 19 views
22

मैं वर्तमान में Boost.Python का उपयोग कर पाइथन के लिए एक C++ एक्सटेंशन लिख रहा हूं। इस एक्सटेंशन में एक फ़ंक्शन एक अपवाद उत्पन्न कर सकता है जिसमें त्रुटि के बारे में जानकारी शामिल है (केवल मानव-पठनीय स्ट्रिंग से परे जो वर्णन हुआ)। मैं उम्मीद कर रहा था कि मैं इस अपवाद को पायथन में निर्यात कर सकता हूं ताकि मैं इसे पकड़ सकूं और अतिरिक्त जानकारी के साथ कुछ कर सकूं।बढ़ावा :: पायथन निर्यात कस्टम अपवाद

उदाहरण के लिए:

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

दुर्भाग्य Boost.Python RuntimeError में सभी सी ++ अपवाद (कि std::exception की उपवर्गों कर रहे हैं) अनुवाद करने के लिए लगता है। मुझे एहसास है कि बूस्ट। पायथन एक कस्टम अपवाद अनुवाद को लागू करने की अनुमति देता है, हालांकि, PyErr_SetObject का उपयोग करने की आवश्यकता है जो PyObject* (अपवाद के प्रकार के लिए) और PyObject* (अपवाद के मूल्य के लिए) लेता है - जिसमें से मुझे पता नहीं है कि कैसे प्राप्त किया जाए मेरे बूस्ट। पायथन कक्षाएं। शायद एक रास्ता है (जो बहुत अच्छा होगा) कि मैं अभी तक नहीं मिला है। अन्यथा क्या कोई कस्टम सी ++ अपवाद निर्यात करने के बारे में जानता है ताकि मैं इसे पायथन में पकड़ सकूं?

+1

** अच्छा प्रश्न और उत्तर! ** यह मेरा दिन बचाया! धन्यवाद। –

+0

बढ़िया! यहां भी बहुत उपयोगी! अगर मैं कर सकता तो मैं 5x वोट करूँगा :) –

उत्तर

25

समाधान किसी भी सामान्य सी ++ वर्ग की तरह अपने अपवाद वर्ग बनाने के लिए है

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

चाल है कि सभी को बढ़ावा देने :: अजगर :: class_ उदाहरणों वस्तु के प्रकार के लिए एक संदर्भ जो उनके ptr के माध्यम से पहुँचा जा सकता है पकड़ है() समारोह। तुम इतनी तरह इस प्राप्त कर सकते हैं आप को बढ़ावा देने के साथ वर्ग रजिस्टर के रूप में :: अजगर:

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

अंत में, जब आप एक अजगर अपवाद को C++ अपवाद अनुवाद कर रहे हैं, तो आप ऐसा प्रकार है:

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

:

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

यहाँ अजगर कोड है कि एक्सटेंशन कहता है:

यहाँ एक पूर्ण काम कर उदाहरण है

4

जैक एडमंड्स द्वारा दिए गए उत्तर में एक पाइथन "अपवाद" वर्ग परिभाषित किया गया है जो Exception (या किसी भी अन्य अंतर्निहित पायथन अपवाद वर्ग) का उत्तराधिकारी नहीं है। इसलिए हालांकि यह

except my_cpp_extension.MyCPPException as e: 
    ... 

साथ पकड़ा जा सकता है यह हमेशा की तरह पकड़ के साथ पकड़ा नहीं किया जा सकता सभी

except Exception as e: 
    ... 

Here है कि इनहेरिट Exception करता है एक कस्टम पायथन अपवाद वर्ग बनाने का तरीका है।

+0

लेकिन यह std :: अपवाद से व्युत्पन्न मौजूदा सी ++ वर्ग को लपेटता नहीं है ... या क्या मुझे कुछ याद आ रहा है? यदि मैं नहीं हूं, तो आपका समाधान वास्तव में इस धागे में प्रश्न का उत्तर नहीं दे रहा है –

+0

@ डैन निरो: सी ++ से पायथन तक अपवाद "निर्यात" करने का सामान्य तरीका इसे लपेटना नहीं है, लेकिन इसे पाइथन अपवाद में अनुवादित करने के लिए 'अपवाद' से। – user763305

+0

मैं आपका पॉइंट देखता हूं। लेकिन अगर यह सी ++ पक्ष है जो अपवाद को बढ़ाता/फेंकता है, तो पाइथन में उस अपवाद को पकड़ने का सबसे अच्छा समाधान कौन सा है? उदाहरण में यहां मैं सी ++ कोड से हटाए गए अपवाद को पकड़ सकता हूं। हालांकि, मैं उस अपवाद को अजगर के भीतर से नहीं बढ़ा सकता। मैं केवल इसे पकड़ सकता हूँ। यदि मैं गलत नहीं हूं, तो आपके समाधान में, आप पाइथन से सी ++ अपवाद बढ़ाने का एक तरीका देते हैं, लेकिन यह C++ कोड से उठाए गए अपवाद का पायथन "जागरूक" नहीं बनाता है। दरअसल यह है, लेकिन ऐसा लगता है कि वे सभी रनटाइम एरर हैं। अगर मुझे कुछ याद आ रहा है, तो मुझे क्षमा करें, मैं बस –

1

variadic टेम्पलेट्स और सामान्यीकृत लैम्ब्डा पर कब्जा करने के लिए धन्यवाद, हम कुछ में Jack Edmond's answer संक्षिप्त कर सकते हैं और अधिक प्रबंधनीय और उपयोगकर्ता से cruft के सभी छिपाने:

template <class E, class... Policies, class... Args> 
py::class_<E, Policies...> exception_(Args&&... args) { 
    py::class_<E, Policies...> cls(std::forward<Args>(args)...); 
    py::register_exception_translator<E>([ptr=cls.ptr()](E const& e){ 
     PyErr_SetObject(ptr, py::object(e).ptr()); 
    }); 
    return cls; 
} 

एक अपवाद के रूप MyCPPException का पर्दाफाश करने के लिए, तुम सिर्फ करने की जरूरत है बाइंडिंग में py::class_ बदलने exception_ रहे हैं:

exception_<MyCPPException>("MyCPPException", py::init<std::string, std::string>()) 
    .add_property("message", &MyCPPException::getMessage) 
    .add_property("extra_data", &MyCPPException::getExtraData) 
; 

और अब हम वापस बूस्ट का ब्योरा करने के लिए कर रहे हैं।पायथन: class_ उदाहरण का नाम देने की आवश्यकता नहीं है, इस अतिरिक्त PyObject* की आवश्यकता नहीं है, और कहीं भी अतिरिक्त कार्य की आवश्यकता नहीं है।

+0

मैंने आपके समाधान की कोशिश की और पाइथन पक्ष पर निम्न त्रुटि प्राप्त की: 'SystemError: अपवाद <वर्ग' MyCPPException '> बेसएक्सप्शन उपclass' नहीं, और' TypeError: बेस अपक्सेप्शन से प्राप्त नहीं होने वाले वर्गों को पकड़ने की अनुमति नहीं है '। बूस्ट। पायथन वी 1.61, पायथन 3.4। –

संबंधित मुद्दे