pybind11: C++ कोड के लिए Python बाइंडिंग बनाना
pybind11 एक हल्की, पूरी तरह से हेडर-ओनली C++ लाइब्रेरी है जो आपको C++ और Python कोड के बीच उच्च-प्रदर्शन वाली बाइंडिंग (bindings) बनाने की अनुमति देती है। यह Boost.Python लाइब्रेरी का एक आधुनिक और अधिक सुविधाजनक विकल्प है। मुख्य विचार यह है कि आप pybind11 के मैक्रोज़ और टेम्पलेट्स का उपयोग करके C++ में थोड़ा सा "ग्लू" कोड लिखते हैं, जो एक डायनामिक लाइब्रेरी ( .so या .pyd फ़ाइल) में कंपाइल होता है। फिर इस फ़ाइल को Python में एक सामान्य मॉड्यूल की तरह इम्पोर्ट किया जा सकता है।
इसकी आवश्यकता क्यों है? वास्तविक प्रोजेक्ट्स में, अक्सर C++ की उच्च गति और निम्न-स्तरीय नियंत्रण को Python की लचीलापन और समृद्ध इकोसिस्टम के साथ जोड़ने की आवश्यकता होती है। आप गति के लिए महत्वपूर्ण कोड (संख्यात्मक एल्गोरिदम, इमेज प्रोसेसिंग, हार्डवेयर के साथ काम) C++ में लिख सकते हैं, और फिर इसे Python से उपयोग कर सकते हैं, जबकि प्रोटोटाइपिंग और डेटा विश्लेषण की सुविधा बनाए रख सकते हैं। pybind11 इस प्रक्रिया को बेहद सरल और सहज बनाता है, स्वचालित रूप से टाइप रूपांतरण, मेमोरी प्रबंधन और अपवादों को संभालता है।
pybind11 के मुख्य लाभ: फ़ंक्शन कॉल में न्यूनतम ओवरहेड, आधुनिक C++ (C++11 और उससे आगे) के लिए पूर्ण समर्थन, मानक कंटेनरों (std::vector, std::map) का Python सूचियों और शब्दकोशों में स्वचालित रूपांतरण, और क्लासेस, मेथड्स और प्रॉपर्टीज को रजिस्टर करने की एक सरल और अभिव्यंजक प्रणाली। यह लाइब्रेरी सक्रिय रूप से विकसित हो रही है और PyTorch, TensorFlow और Open3D जैसे बड़े प्रोजेक्ट्स में उपयोग की जाती है।
इंस्टॉलेशन
pybind11 एक हेडर-ओनली लाइब्रेरी है, इसलिए इसकी इंस्टॉलेशन आपके प्रोजेक्ट में हेडर फ़ाइलों को कॉपी करने जितनी सरल है। सबसे आसान और अनुशंसित तरीका pip पैकेज मैनेजर का उपयोग करना है, जो लाइब्रेरी को सिस्टम में इंस्टॉल करेगा और कंपाइलेशन पथ प्राप्त करने के लिए pybind11-config उपयोगिता प्रदान करेगा:
pip install pybind11
इंस्टॉलेशन के बाद, आप निम्न कमांड चलाकर जांच सकते हैं कि सब कुछ ठीक से काम कर रहा है:
pybind11-config --includes
यह pybind11 हेडर फ़ाइलों को शामिल करने के लिए आवश्यक कंपाइलर फ़्लैग्स को आउटपुट करेगा। मॉड्यूल को कंपाइल करने के लिए, आपको एक C++ कंपाइलर (g++, clang, MSVC) और Python हेडर (आमतौर पर Python के साथ इंस्टॉल होते हैं) की भी आवश्यकता होगी। CMake या सीधे g++ के माध्यम से कंपाइलेशन का उदाहरण:
c++ -O3 -Wall -shared -std=c++11 -fPIC $(python3 -m pybind11 --includes) example.cpp -o example$(python3-config --extension-suffix)
त्वरित शुरुआत: न्यूनतम कार्यशील उदाहरण
निम्नलिखित सामग्री के साथ एक example.cpp फ़ाइल बनाएं:
#include <pybind11/pybind11.h>
namespace py = pybind11;
int add(int i, int j) {
return i + j;
}
PYBIND11_MODULE(example, m) {
m.doc() = "pybind11 example plugin";
m.def("add", &add, "A function that adds two numbers");
}
इसे कंपाइल करें (python3 को अपने इंटरप्रेटर से बदलें):
c++ -O3 -Wall -shared -std=c++11 -fPIC $(python3 -m pybind11 --includes) example.cpp -o example$(python3-config --extension-suffix)
अब आप Python से मॉड्यूल का उपयोग कर सकते हैं:
import example
result = example.add(3, 4)
print(result) # आउटपुट: 7
print(example.__doc__) # आउटपुट: pybind11 example plugin
pybind11 के मुख्य तरीके और क्लासेस
नीचे लाइब्रेरी के प्रमुख फ़ंक्शन और क्लासेस दिए गए हैं जिनका उपयोग बाइंडिंग बनाने के लिए किया जाता है।
1. PYBIND11_MODULE(name, variable)
सिग्नेचर: PYBIND11_MODULE(name, variable) (मैक्रो)
यह क्या करता है: Python मॉड्यूल के लिए एंट्री पॉइंट को परिभाषित करता है। यह एक इनिशियलाइज़ेशन फ़ंक्शन बनाता है जो स्वचालित रूप से कॉल होता है जब मॉड्यूल Python में इम्पोर्ट किया जाता है। name पैरामीटर मॉड्यूल का नाम है (बिना कोट्स के), और variable एक py::module_ ऑब्जेक्ट है जिसका उपयोग फ़ंक्शन, क्लासेस और अन्य चीज़ों को रजिस्टर करने के लिए किया जाता है।
उपयोग उदाहरण: ऊपर दिए गए त्वरित शुरुआत उदाहरण में देखें।
2. m.def(name, function, description)
सिग्नेचर: m.def(const char *name, Callable function, const char *docstring = "")
यह क्या करता है: एक C++ फ़ंक्शन को Python फ़ंक्शन के रूप में एक्सपोर्ट करता है। name Python में फ़ंक्शन का नाम है, function C++ फ़ंक्शन का पॉइंटर या लैम्ब्डा है, और docstring वैकल्पिक दस्तावेज़ीकरण स्ट्रिंग है। pybind11 स्वचालित रूप से तर्कों और रिटर्न वैल्यू को परिवर्तित करता है।
उपयोग उदाहरण: m.def("add", &add, "दो संख्याओं को जोड़ने वाला फ़ंक्शन");
3. py::class_<T>(module, name)
सिग्नेचर: py::class_<T>(py::module_ &m, const char *name)
यह क्या करता है: C++ क्लास T को Python में रजिस्टर करता है। यह एक बिल्डर पैटर्न प्रदान करता है जिसमें आप .def(), .def_readwrite(), .def_readonly() आदि जैसे मेथड्स को चेन कर सकते हैं ताकि क्लास के मेथड्स और प्रॉपर्टीज को परिभाषित किया जा सके।
उपयोग उदाहरण:
py::class_<MyClass>(m, "MyClass")
.def(py::init<int>()) // कंस्ट्रक्टर को बाइंड करें
.def("my_method", &MyClass::my_method)
.def_readwrite("my_attribute", &MyClass::my_attribute);
4. .def(py::init<Args...>())
सिग्नेचर: .def(py::init<Args...>())
यह क्या करता है: C++ क्लास के कंस्ट्रक्टर को Python में एक्सपोज़ करता है। Args... कंस्ट्रक्टर के पैरामीटर प्रकार हैं। आप कई कंस्ट्रक्टर को बाइंड करने के लिए कई py::init<>() कॉल को चेन कर सकते हैं।
उपयोग उदाहरण: .def(py::init<int, double>()) एक कंस्ट्रक्टर को बाइंड करता है जो एक int और एक double लेता है।
5. .def_readwrite(name, &Class::member) और .def_readonly(name, &Class::member)
सिग्नेचर: .def_readwrite(const char *name, Type Class::*member) और .def_readonly(const char *name, Type Class::*member)
यह क्या करता है: C++ क्लास के पब्लिक डेटा मेंबर्स को Python प्रॉपर्टीज के रूप में एक्सपोज़ करता है। def_readwrite रीड-राइट एक्सेस प्रदान करता है, जबकि def_readonly केवल रीड-ओनली एक्सेस प्रदान करता है।
उपयोग उदाहरण: .def_readwrite("value", &MyClass::value)
6. py::array_t<T> और py::buffer_info
सिग्नेचर: py::array_t<T>(py::buffer buffer) और py::buffer_info request(py::buffer &buf)
यह क्या करता है: NumPy arrays के साथ कुशलतापूर्वक इंटरऑपरेट करने के लिए उपयोग किया जाता है। py::array_t<T> एक टाइप-सेफ NumPy array रैपर है, और py::buffer_info बफर प्रोटोकॉल के माध्यम से अंतर्निहित डेटा तक पहुंच प्रदान करता है। यह डेटा कॉपी किए बिना बड़े डेटासेट को साझा करने की अनुमति देता है।
उपयोग उदाहरण:
void process_array(py::array_t<double> input) {
py::buffer_info buf = input.request();
double *ptr = static_cast<double*>(buf.ptr);
// अब ptr का उपयोग करके डेटा तक पहुंचें
}
7. py::object और py::module_::import()
सिग्नेचर: py::object py::module_::import(const char *name)
यह क्या करता है: C++ कोड से Python मॉड्यूल को इम्पोर्ट करने और उसके फ़ंक्शन/ऑब्जेक्ट को कॉल करने की अनुमति देता है। py::object एक जेनेरिक Python ऑब्जेक्ट का रैपर है।
उपयोग उदाहरण:
py::object math = py::module_::import("math");
py::object result = math.attr("sqrt")(16);
double sqrt_val = result.cast<double>(); // sqrt_val = 4.0
8. py::args और py::kwargs
सिग्नेचर: py::args और py::kwargs (प्रकार)
यह क्या करता है: C++ फ़ंक्शन को वेरिएबल-लेंथ आर्गुमेंट्स (*args) और कीवर्ड आर्गुमेंट्स (**kwargs) स्वीकार करने की अनुमति देता है। यह Python फ़ंक्शन सिग्नेचर को मिरर करने के लिए उपयोगी है।
उपयोग उदाहरण:
void flexible_function(py::args args, py::kwargs kwargs) {
// args और kwargs को संभालें
}
m.def("flexible", &flexible_function);
9. py::cast<T>(object)
सिग्नेचर: py::cast<T>(py::handle obj)
यह क्या करता है: एक Python ऑब्जेक्ट को C++ प्रकार T में परिवर्तित करता है। यदि रूपांतरण संभव नहीं है तो यह एक अपवाद फेंकता है। यह py::object से C++ मान निकालने का मानक तरीका है।
उपयोग उदाहरण: int val = py::cast<int>(some_py_object);
10. py::stl.h और स्वचालित रूपांतरण
सिग्नेचर: #include <pybind11/stl.h>
यह क्या करता है: यह हेडर C++ STL कंटेनरों (जैसे std::vector, std::map, std::set) और Python कंटेनरों (सूची, शब्दकोश, सेट) के बीच स्वचालित रूपांतरण को सक्षम करता है। इस हेडर को शामिल करने के बाद, आप इन प्रकारों को फ़ंक्शन पैरामीटर और रिटर्न वैल्यू के रूप में उपयोग कर सकते हैं, और pybind11 स्वचालित रूप से रूपांतरण को संभालेगा।
उपयोग उदाहरण:
#include <pybind11/stl.h>
std::vector<int> get_vector() { return {1, 2, 3}; }
// Python में यह एक सूची [1, 2, 3] के रूप में दिखाई देगा
निष्कर्ष
pybind11 C++ और Python को जोड़ने के लिए एक शक्तिशाली और उपयोगकर्ता-अनुकूल लाइब्रेरी है। इसके साथ, आप अपने C++ कोड की गति और दक्षता को Python की सादगी और लचीलापन के साथ जोड़ सकते हैं। ऊपर दिए गए तरीके और उदाहरण आपको शुरुआत करने में मदद करेंगे। अधिक जानकारी के