स्थितिगतिशील रूप rethrowing आत्म परिभाषित सी ++ बड़ा घूँट
का उपयोग कर अजगर अपवाद के रूप में अपवाद मैं एक अजगर भाषा एक सी ++ बड़ा घूँट का उपयोग कर एपीआई के लिए बाध्यकारी बनाना चाहते हैं। कुछ एपीआई फ़ंक्शंस अपवाद फेंक सकते हैं।
std::exception
-> API::Exception
-> API::NetworkException
-> API::TimeoutException
-> API::UnreachableException
-> API::InvalidAddressException
वांछित व्यवहार इस प्रकार है::
सभी प्रकार के अपवाद आवरण के रूप में एक मिलान अजगर वर्ग होना चाहिए सी ++ आवेदन आत्म परिभाषित अपवाद के एक पदानुक्रम, इस उदाहरण की तरह है। ये रैपर वर्ग मान्य पायथन अपवाद होना चाहिए।
API कॉल एक C++ अपवाद फेंकता है, यह पकड़ा होना चाहिए। इसी अजगर अपवाद (अर्थात पकड़ा C++ अपवाद के आवरण वर्ग) होना चाहिए फेंक दिया।
यह एक गतिशील प्रक्रिया होना चाहिए: अजगर अपवाद प्रकार, क्रम पर निर्णय लिया जाता है केवल पकड़ा C++ अपवाद के क्रम प्रकार के आधार पर। इस तरह, SWIG इंटरफ़ेस फ़ाइल में पूर्ण अपवाद पदानुक्रम का वर्णन करने की कोई आवश्यकता नहीं है।
समस्याओं और प्रश्नों
आवरण वर्गों कोई अजगर अपवाद हैं।
बड़ा घूँट सभी आत्म परिभाषित अपवाद के लिए आवरण वर्गों बनाता है (किसी अन्य वर्ग के लिए) की तरह है, इन कक्षाओं अपवाद अजगर नहीं कर रहे हैं। आधार अपवाद (उदाहरण में
API::Exception
) का आवरणObject
बजायBaseException
, पायथन वर्ग जिनमें से अजगर में सभी अपवादों को लिया जाना चाहिए फैली हुई है।इसके अलावा, यह बड़ा घूँट एक माता पिता के वर्ग मैन्युअल रूप से जोड़ जाने के लिए संभव प्रतीत नहीं होता। नोट
%typemap(javabase)
के उपयोग के माध्यम से जावा के साथ SWIG का उपयोग करते समय यह संभव है (विवरण के लिए SWIG documentation देखें)।कैसे Python C API उपयोगकर्ता परिभाषित अपवाद फेंक कर सकते हैं?
पायथन सी एपीआई से पाइथन अपवाद फेंकने का सबसे आम तरीका
PyErr_SetString
[reference] पर कॉल करके है। यह नीचे डेमो आवेदन में भी दिखाया गया है।लेकिन इस मानक (बिल्ट-इन) अजगर को छोड़कर केवल मामूली बात है, क्योंकि उन्हें संदर्भ अजगर सी एपीआई में वैश्विक चर [reference] में संग्रहीत हैं।
मुझे पता है कि स्व-परिभाषित अपवादों के संदर्भ प्राप्त करने के लिए
PyErr_NewException
[reference] विधि है, लेकिन मुझे यह काम नहीं मिला।Python C API रनटाइम पर C++ प्रकार का मूल्यांकन कैसे कर सकता है और फिर नाम से संबंधित पायथन रैपर वर्ग का पता लगा सकता है?
मुझे लगता है एक अजगर वर्ग अजगर सी एपीआई के reflection part के माध्यम से, कार्यावधि में नाम से खोजा जा सकता है। क्या यह जाने का रास्ता है? और यह अभ्यास में कैसे किया जाता है?
डेमो आवेदन
इस समस्या के साथ प्रयोग करने के लिए, मैं एक छोटे से सी ++ एपीआई एक भी समारोह है कि किसी संख्या का फ़ैक्टोरियल की गणना करता है के साथ बनाया। इसमें न्यूनतम आत्म-परिभाषित अपवाद पदानुक्रम है, जिसमें केवल एक वर्ग TooBigException
शामिल है।
नोट करें कि यह अपवाद सामान्य समस्या में आधार अपवाद के रूप में कार्य करता है और एप्लिकेशन को इसके किसी भी उप-वर्ग के साथ काम करना चाहिए। इसका मतलब है कि समाधान केवल पाइथन (इसे नीचे देखें) में पुनर्स्थापित करने के लिए पकड़े गए अपवाद के गतिशील (यानी रनटाइम) प्रकार का उपयोग कर सकता है।
// File: numbers.h
namespace numbers {
int fact(int n);
}
// File: numbers.cpp
#include "TooBigException.h"
namespace numbers {
int fact(int n) {
if (n > 10) throw TooBigException("Value too big", n);
else if (n <= 1) return 1;
else return n*fact(n-1);
}
}
// File: TooBigException.h
namespace numbers {
class TooBigException: public std::exception {
public:
explicit TooBigException(const std::string & inMessage,
const int inValue);
virtual ~TooBigException() throw() {}
virtual const char* what() const throw();
const std::string & message() const;
const int value() const;
private:
std::string mMessage;
int mValue;
};
}
// File: TooBigException.cpp
#include "TooBigException.h"
namespace numbers {
TooBigException::TooBigException(const std::string & inMessage, const int inValue):
std::exception(),
mMessage(inMessage),
mValue(inValue)
{
}
const char* TooBigException::what() const throw(){
return mMessage.c_str();
}
const std::string & TooBigException::message() const {
return mMessage;
}
const int TooBigException::value() const {
return mValue;
}
}
प्राप्त करने के लिए अजगर बाध्यकारी मैं निम्नलिखित बड़ा घूँट इंटरफ़ेस फ़ाइल का उपयोग:
// File: numbers.i
%module numbers
%include "stl.i"
%include "exception.i"
%{
#define SWIG_FILE_WITH_INIT
#include "TooBigException.h"
#include "numbers.h"
%}
%exception {
try {
$action
}
catch (const numbers::TooBigException & e) {
// This catches any self-defined exception in the exception hierarchy,
// because they all derive from this base class.
<TODO>
}
catch (const std::exception & e)
{
SWIG_exception(SWIG_RuntimeError, (std::string("C++ std::exception: ") + e.what()).c_str());
}
catch (...)
{
SWIG_exception(SWIG_UnknownError, "C++ anonymous exception");
}
}
%include "TooBigException.h"
%include "numbers.h"
तो एपीआई के लिए हर कॉल है
डेमो आवेदन के पूर्ण स्रोत कोड इस प्रकार है एक कोशिश-पकड़ ब्लॉक द्वारा लपेटा। हमारे मूल प्रकार के पहले अपवाद पकड़े और संभाले जाते हैं। फिर SWIG अपवाद लाइब्रेरी का उपयोग करके अन्य सभी अपवाद पकड़े जाते हैं और पुनर्स्थापित होते हैं।
नोट numbers::TooBigException
में से किसी उपवर्ग पकड़ा है और उनके गतिशील की रैपर (अर्थात क्रम) टाइप फेंक दिया जाना चाहिए, न कि उनका स्थिर का आवरण (अर्थात समय संकलन) प्रकार है, जो हमेशा है TooBigException
!
परियोजना एक लिनक्स मशीन पर निम्न आदेशों को क्रियान्वित करने से आसानी से बनाया जा सकता है:
$ swig -c++ -python numbers.i
$ g++ -fPIC -shared TooBigException.cpp numbers.cpp numbers_wrap.cxx \
-I/usr/include/python2.7 -o _numbers.so
वर्तमान कार्यान्वयन
मेरे वर्तमान कार्यान्वयन अभी भी (सफलतापूर्वक) एक निश्चित मानक अजगर अपवाद फेंकता है।
PyErr_SetString(PyExc_Exception, (std::string("C++ self-defined exception ") + e.what()).c_str());
return NULL;
कौन सा अजगर में निम्नलिखित (उम्मीद) व्यवहार देता है:: कोड ऊपर <TODO>
तो ले लेती है
>>> import numbers
>>> fact(11)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
Exception: C++ self-defined exception Value too big
मुझे सच में यकीन नहीं है कि आप क्या चाहते हैं, लेकिन क्या आपने देखा है कि यह कोड आपके दूसरे मामले में मदद करता है या नहीं? 'फेंक;' – PlasmaHH