सी ++ सिग मेलिंग सूची से यह शानदार समाधान मिला।
सी ++ कक्षा में std::map<std::string, boost::python::object>
लागू करें, फिर उस std :: मानचित्र से पढ़ने और लिखने के लिए __getattr__()
और __setattr__()
ओवरलोड करें। फिर इसे सामान्य रूप से boost::python::ptr()
के साथ पाइथन पर भेजें, किसी ऑब्जेक्ट को C++ पक्ष पर रखने की आवश्यकता नहीं है या एक पायथन पर भेजें। यह पूरी तरह से काम करता है।
संपादित करें: मैंने यह भी पाया कि मुझे __setattr__()
फ़ंक्शन को विशेष तरीके से ओवरराइड करना था क्योंकि यह add_property()
के साथ जोड़े गए चीज़ों को तोड़ रहा था। उन चीजों को प्राप्त करते समय ठीक काम किया, क्योंकि पाइथन __getattr__()
पर कॉल करने से पहले कक्षा के गुणों की जांच करता है, लेकिन __setattr__()
के साथ ऐसी कोई जांच नहीं है। यह सिर्फ इसे सीधे कहते हैं। तो मुझे इसे एक पूर्ण समाधान में बदलने के लिए कुछ बदलाव करना पड़ा।
boost::python::object PyMyModule_global;
एक वर्ग (आप इसे में जोड़ना चाहते हैं जो कुछ भी अन्य जानकारी के साथ) के रूप में बनाएँ::
class MyClass
{
public:
//Python checks the class attributes before it calls __getattr__ so we don't have to do anything special here.
boost::python::object Py_GetAttr(std::string str)
{
if(dict.find(str) == dict.end())
{
PyErr_SetString(PyExc_AttributeError, JFormat::format("MyClass instance has no attribute '{0}'", str).c_str());
throw boost::python::error_already_set();
}
return dict[str];
}
//However, with __setattr__, python doesn't do anything with the class attributes first, it just calls __setattr__.
//Which means anything that's been defined as a class attribute won't be modified here - including things set with
//add_property(), def_readwrite(), etc.
void Py_SetAttr(std::string str, boost::python::object val)
{
try
{
//First we check to see if the class has an attribute by this name.
boost::python::object obj = PyMyModule_global["MyClass"].attr(str.c_str());
//If so, we call the old cached __setattr__ function.
PyMyModule_global["MyClass"].attr("__setattr_old__")(ptr(this), str, val);
}
catch(boost::python::error_already_set &e)
{
//If it threw an exception, that means that there is no such attribute.
//Put it on the persistent dict.
PyErr_Clear();
dict[str] = val;
}
}
private:
std::map<std::string, boost::python::object> dict;
};
पहले एक वैश्विक चर बनाने: यहाँ समाधान का पूरा कार्यान्वयन है फिर पाइथन मॉड्यूल को निम्नानुसार परिभाषित करें, जो भी अन्य डिफ और गुण आप चाहते हैं:
BOOST_PYTHON_MODULE(MyModule)
{
boost::python::class_<MyClass>("MyClass", boost::python::no_init)
.def("__getattr__", &MyClass::Py_GetAttr)
.def("__setattr_new__", &MyClass::Py_SetAttr);
}
void PyInit()
{
//Initialize module
PyImport_AppendInittab("MyModule", &initMyModule);
//Initialize Python
Py_Initialize();
//Grab __main__ and its globals
boost::python::object main = boost::python::import("__main__");
boost::python::object global = main.attr("__dict__");
//Import the module and grab its globals
boost::python::object PyMyModule = boost::python::import("MyModule");
global["MyModule"] = PyMyModule;
PyMyModule_global = PyMyModule.attr("__dict__");
//Overload MyClass's setattr, so that it will work with already defined attributes while persisting new ones
PyMyModule_global["MyClass"].attr("__setattr_old__") = PyMyModule_global["MyClass"].attr("__setattr__");
PyMyModule_global["MyClass"].attr("__setattr__") = PyMyModule_global["MyClass"].attr("__setattr_new__");
}
एक बार जब आप यह सब किया है, तो आप सी ++ के लिए खत्म हो अजगर में किए गए उदाहरण में परिवर्तन लागू करने के लिए सक्षम हो जाएगा:तो अजगर आरंभ कर देगा। किसी विशेषता के रूप में C++ में परिभाषित कुछ भी ठीक से संभाला जाएगा, और जो भी नहीं है उसे कक्षा के __dict__
के बजाय dict
में जोड़ा जाएगा।
एक समाधान मिला। डीईएफ़ ProcessEvent (घटना, obj): वैश्विक() [घटना] (obj.PyObj) लौट C++ में, मैं जोड़ा एक 'बढ़ावा देने :: अजगर :: object' अजगर में, मैं एक समारोह जोड़ा मेरे सी ++ वर्ग में 'पायओब्ज' नाम दिया गया है, जिसे 'बूस्ट :: पायथन :: पीआरटी (यह)' में शुरू किया गया है, और इसके साथ मेरी घटनाओं को बुलाया गया है, जिस घटना को मैं पहले पैरामीटर के रूप में कॉल करना चाहता हूं और ' boost :: python :: ptr' ऑब्जेक्ट में मैं इसे दूसरे के रूप में पास करना चाहता हूं। यह काम करता है जैसा कि मैंने आशा की थी - जब मैंने एक घटना में एक विशेषता जोड़ा, तो यह तब भी था जब मैंने इसे दूसरे पास कर दिया। शायद सबसे अच्छा समाधान नहीं है ... लेकिन, यह काम करता है। –