__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 = 4
n
को पुनर्निर्मित करता है; यह 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