2012-07-12 24 views
5

मैं एक वर्ग निम्न के समान है के लिए बाध्यकारी:अजगर सी ++ ऑपरेटर ओवरलोडिंग

class A { 
    vector<double> v; 
    double& x(int i) { return v[2*i]; } 
    double& y(int i) { return v[2*i+1]; } 
    double x(int i) const { return v[2*i]; } 
    double y(int i) const { return v[2*i+1]; } 
} 

मैं निम्नलिखित पायथन कोड काम करना चाहते हैं:

a = A() 
a.x[0] = 4 
print a.x[0] 

मैं __setattr__ और __getattr__ की सोच रहा था, लेकिन यह सुनिश्चित नहीं है कि यह काम करता है। एक वैकल्पिक निम्नलिखित अजगर को लागू करना है:

a = A() 
a['x', 0] = 4 
print a['x', 0] 

के रूप में पिछले एक के रूप में अच्छा नहीं है, लेकिन लागू करने के लिए आसान हो सकता है (__slice__ साथ?)।

पीएस। मैं बाध्यकारी करने के लिए सिप का उपयोग कर रहा हूँ।

धन्यवाद।

उत्तर

6

__getattr__ और कस्टम %MethodCode के साथ यह संभव है;

  • एक मध्यवर्ती प्रकार/वस्तु की जरूरत है, के रूप में बनाया जाना a.x एक वस्तु है कि __getitem__ और __setitem__ प्रदान करता है वापस आ जाएगी: तथापि, वहाँ कुछ बिंदुओं को ध्यान में रखना करने के लिए कर रहे हैं। सीमाओं के बाहर होने पर दोनों विधियों को IndexError उठाना चाहिए, क्योंकि यह __getitem__ के माध्यम से पुनरावर्तित पुराने प्रोटोकॉल का हिस्सा है; इसके बिना, a.x से अधिक होने पर एक क्रैश होगा।
  • वेक्टर के जीवनकाल की गारंटी के लिए, a.x ऑब्जेक्ट को वेक्टर (a) के स्वामित्व वाले ऑब्जेक्ट का संदर्भ बनाए रखने की आवश्यकता है। विशेष रूप से जब त्रुटि मामलों दौरान संदर्भ गिनती प्रबंधित करने की आवश्यकता

    a = A() 
    x = a.x 
    a = None # If 'x' has a reference to 'a.v' and not 'a', then it may have a 
         # dangling reference, as 'a' is refcounted by python, and 'a.v' is 
         # not refcounted. 
    
  • %MethodCode लेखन, मुश्किल हो सकता है: निम्नलिखित कोड पर विचार करें। इसे पायथन सी एपीआई और एसआईपी की समझ की आवश्यकता है।

कोई वैकल्पिक समाधान के लिए, पर विचार करें:

  • डिजाइन अजगर बाइंडिंग सुविधा प्रदान करने के।
  • पाइथन में डिज़ाइन क्लास (एसएस) बाइंडोनिक इंटरफेस प्रदान करने के लिए बाइंडिंग का उपयोग करता है।

    • यह बहुत आसान है:

    जबकि दृष्टिकोण कुछ कमियां, कोड के रूप में इस तरह के और अधिक फ़ाइलें पुस्तकालय के साथ वितरित करने के लिए आवश्यकता हो सकती है कि में अलग किया जाता है, यह कुछ प्रमुख लाभ प्रदान करता है सी या इंटरऑपरेबिलिटी लाइब्रेरी के इंटरफेस की तुलना में अजगर में एक पाइथोनिक इंटरफ़ेस को लागू करने के लिए।

  • स्लाइसिंग, इटरेटर आदि के लिए समर्थन सी एपीआई के माध्यम से इसे प्रबंधित करने के बजाय, पाइथन में अधिक स्वाभाविक रूप से कार्यान्वित किया जा सकता है।
  • अंतर्निहित स्मृति के जीवनकाल को प्रबंधित करने के लिए पाइथन के कचरा कलेक्टर का लाभ उठा सकता है।
  • पायथन और सी ++ के बीच अंतःक्रियाशीलता प्रदान करने के लिए जो भी कार्यान्वयन किया जा रहा है, उससे पाइथोनिक इंटरफेस का उपयोग किया जाता है।एक चापलूसी और सरल बाध्यकारी इंटरफ़ेस के साथ, बूस्ट.पथन और एसआईपी जैसे कार्यान्वयन के बीच बदलना बहुत आसान है।

यहाँ एक चलना के माध्यम से इस दृष्टिकोण का प्रदर्शन है। सबसे पहले, हम बुनियादी A कक्षा से शुरू करते हैं। इस उदाहरण में, मैंने एक कन्स्ट्रक्टर प्रदान किया है जो कुछ प्रारंभिक डेटा सेट करेगा।

a.hpp:

#ifndef A_HPP 
#define A_HPP 

#include <vector> 

class A 
{ 
    std::vector<double> v; 
public: 
    A() { for (int i = 0; i < 6; ++i) v.push_back(i); } 
    double& x(int i)   { return v[2*i];  } 
    double x(int i) const { return v[2*i];  } 
    double& y(int i)   { return v[2*i+1];  } 
    double y(int i) const { return v[2*i+1];  } 
    std::size_t size() const { return v.size()/2; } 
}; 

#endif // A_HPP 

बाइंडिंग करने से पहले, की सुविधा देता है A इंटरफ़ेस जांच करते हैं। मुहावरों से अधिक भार का समर्थन करने के लिए जब तर्क प्रकार/मायने रखता ही कर रहे हैं असफल हो जायेगी

  • अजगर अतिभारित विधियाँ का समर्थन नहीं करता है, और: एक ओर जहां यह सी ++ में उपयोग करने के लिए एक आसान इंटरफेस है, यह अजगर में कुछ कठिनाइयों है।
  • दो भाषाओं के बीच एक डबल (पायथन में फ्लोट) के संदर्भ की अवधारणा दो भाषाओं के बीच अलग है। पायथन में, फ्लोट एक अपरिवर्तनीय प्रकार है, इसलिए इसका मूल्य बदला नहीं जा सकता है। उदाहरण के लिए, पाइथन में a.x[0] से float ऑब्जेक्ट को संदर्भित करने के लिए n = a.x[0] बंड n को बाइंडन में ऑब्जेक्ट का संदर्भ देने के लिए। ऑब्जेक्ट को संदर्भित करने के लिए असाइनमेंट n = 4n को पुनर्निर्मित करता है; यह a.x[0]4 पर सेट नहीं करता है।
  • __len__int की अपेक्षा करता है, std::size_t नहीं।

चलिए एक बुनियादी मध्यवर्ती वर्ग बनाते हैं जो बाइंडिंग को सरल बनाने में मदद करेगा।

pya.hpp:

#ifndef PYA_HPP 
#define PYA_HPP 

#include "a.hpp" 

struct PyA: A 
{ 
    double get_x(int i)   { return x(i); } 
    void set_x(int i, double v) { x(i) = v; } 
    double get_y(int i)   { return y(i); } 
    void set_y(int i, double v) { y(i) = v; } 
    int length()     { return size(); } 
}; 

#endif // PYA_HPP 

वाह! PyA अब सदस्य फ़ंक्शंस प्रदान करता है जो संदर्भ वापस नहीं करते हैं, और लंबाई int के रूप में वापस कर दी जाती है। यह इंटरफेस का सबसे अच्छा नहीं है, बाइंडिंग को वांछित इंटरफ़ेस की बजाय आवश्यक कार्यक्षमता प्रदान करने के लिए डिज़ाइन किया गया है।

अब, कुछ सरल बाइंडिंग लिखने दें जो cexample मॉड्यूल में कक्षा A बनाएंगे।

यहाँ एसआईपी में बाइंडिंग है:

%Module cexample 

class PyA /PyName=A/ 
{ 
%TypeHeaderCode 
#include "pya.hpp" 
%End 
public: 
    double get_x(int); 
    void set_x(int, double); 
    double get_y(int); 
    void set_y(int, double); 
    int __len__(); 
    %MethodCode 
    sipRes = sipCpp->length(); 
    %End 
}; 

या यदि आप Boost.Python पसंद करते हैं: PyA मध्यवर्ती वर्ग के कारण

#include "pya.hpp" 
#include <boost/python.hpp> 

BOOST_PYTHON_MODULE(cexample) 
{ 
    using namespace boost::python; 
    class_<PyA>("A") 
    .def("get_x", &PyA::get_x ) 
    .def("set_x", &PyA::set_x ) 
    .def("get_y", &PyA::get_y ) 
    .def("set_y", &PyA::set_y ) 
    .def("__len__", &PyA::length) 
    ; 
} 

, बाइंडिंग के दोनों काफी सरल कर रहे हैं। इसके अतिरिक्त, इस दृष्टिकोण के लिए कम एसआईपी और पायथन सी एपीआई ज्ञान की आवश्यकता है, क्योंकि इसे %MethodCode ब्लॉक के भीतर कम कोड की आवश्यकता है।

अंत में, example.py बनाने कि वांछित pythonic इंटरफेस प्रदान करेगा:

class A: 
    class __Helper: 
     def __init__(self, data, getter, setter): 
      self.__data = data 
      self.__getter = getter 
      self.__setter = setter 

     def __getitem__(self, index): 
      if len(self) <= index: 
       raise IndexError("index out of range") 
      return self.__getter(index) 

     def __setitem__(self, index, value): 
      if len(self) <= index: 
       raise IndexError("index out of range") 
      self.__setter(index, value) 

     def __len__(self): 
      return len(self.__data) 

    def __init__(self): 
     import cexample 
     a = cexample.A() 
     self.x = A.__Helper(a, a.get_x, a.set_x) 
     self.y = A.__Helper(a, a.get_y, a.set_y) 

अंत में, बाइंडिंग कार्यक्षमता हम की जरूरत है प्रदान करते हैं और अजगर इंटरफ़ेस हम चाहते हैं बनाता है। बाइंडिंग इंटरफ़ेस प्रदान करना संभव है; हालांकि, इसे दो भाषाओं और बाध्यकारी कार्यान्वयन के बीच मतभेदों की समृद्ध समझ की आवश्यकता हो सकती है।

>>> from example import A 
>>> a = A() 
>>> for x in a.x: 
... print x 
... 
0.0 
2.0 
4.0 
>>> a.x[0] = 4 
>>> for x in a.x: 
... print x 
... 
4.0 
2.0 
4.0 
>>> x = a.x 
>>> a = None 
>>> print x[0] 
4.0
संबंधित मुद्दे