Re: [C++-sig] PyEval_EvalCode
My question probably derives from ignorance of the Python way. I kind of assumed people would advocate defining classes and methods, and then calling those methods. You apparently see things otherwise. One thing I'm considering is to make one layer of abstraction, and define a Python function which takes a dictionary and a script file name. I think this level would make the code more instrumentable than with all the stuff in C++. Alan Baljeu - Original Message From: Stefan Seefeld <[EMAIL PROTECTED]> To: Development of Python/C++ integration Sent: Tuesday, November 11, 2008 4:25:00 PM Subject: Re: [C++-sig] PyEval_EvalCode Alan Baljeu wrote: > I was reading some legacy code we have here, and discovered an unexpected > idiom. Starting from C++, we create a dictionary, store a few named > constants in there, and then call PyEval_EvalCode passing in the dictionary. > The code it calls is a bunch of python files generated from a CAD model, with > no function definitions. It works of course. Question is, what do you think > of this approach? What is a more typical idiom? > I don't quite understand the question. What I think of this approach depends a lot on what you use it for. Typical for what ? Having a C++ application run some python script that has access to some of the application state (i.e., whatever you expose through the dictionary) is certainly a fine way to make your application scriptable. (FWIW, boost.python offers 'exec()' and 'eval()' for this.) Regards, Stefan -- ...ich hab' noch einen Koffer in Berlin... ___ Cplusplus-sig mailing list Cplusplus-sig@python.org http://mail.python.org/mailman/listinfo/cplusplus-sig __ Looking for the perfect gift? Give the gift of Flickr! http://www.flickr.com/gift/ ___ Cplusplus-sig mailing list Cplusplus-sig@python.org http://mail.python.org/mailman/listinfo/cplusplus-sig
Re: [C++-sig] PyEval_EvalCode
Alan Baljeu wrote: My question probably derives from ignorance of the Python way. I kind of assumed people would advocate defining classes and methods, and then calling those methods. You apparently see things otherwise. Not really. I just see it as an orthogonal problem to the question you asked in your previous mail. One thing I'm considering is to make one layer of abstraction, and define a Python function which takes a dictionary and a script file name. I think this level would make the code more instrumentable than with all the stuff in C++. Again, without at last a little bit of context (what is your application doing, and what part of that would you like to control via python scripts) it's very hard to have a meaningful discussion. Also, I'm not sure whether your question is really specific to 'eval', or whether you also include 'exec' into this discussion (eval evaluates an expression and returns the result, while exec runs code, not necessarily returning anything). It seems your question is all about the boundary / interface between the (C++) application and the script that gets invoked: What should the content of the dictionary be, and what is the script expected to do with it ? In the most trivial case such a script could simply store named values (numbers, strings) into the dictionary, which then get evaluated by the application. The script thus becomes a mere configuration file. Alternatively, you can inject functions or even objects into the dictionary, which the script is expected to interact with. How much 'Object-Orientedness' makes sense really depends on your needs, which you haven't talked about yet. Regards, Stefan -- ...ich hab' noch einen Koffer in Berlin... ___ Cplusplus-sig mailing list Cplusplus-sig@python.org http://mail.python.org/mailman/listinfo/cplusplus-sig
Re: [C++-sig] PyEval_EvalCode
>It seems your question is all about the boundary / interface between the (C++) >application and the script that gets invoked: What should the content of the >dictionary be, and what is the script expected to do with it ? >In the most trivial case such a script could simply store named values >(numbers, strings) into the dictionary, which then get evaluated >by the application. The script thus becomes a mere configuration file. >Alternatively, you can inject functions or even objects into the dictionary, >which the script is expected to interact with. How much 'Object-Orientedness' >makes sense really depends on your needs, which you haven't >talked about yet. > >Regards, > Stefan Okay I'll try. I'm growing a CAD plug-in DLL. I have decided that the edit/compile/run/test cycle is too slow both because C++ is a bear, and because both compile and run steps are extremely slow in my environment. To solve this, I intend to write as much Python as possible, to drive C++ objects, so I won't have to recompile, or restart my environment. (Previous use of python had a slightly different goal: use Python minimally for a dynamic modeling problem) So Python code will consist of interactive and non-interactive scripts. These scripts receive objects, work with them, and return other objects. There are no persistent Python objects. There are probably Python classes designed as temporary wrappers of C++ classes. Steps 1) Embed Python in this C++ plug-in. [Done.] 2) Expose C++ objects (functions and/or data) defined by the plugin to Python. 3) Write code in Python to create and manipulate those objects. (exec, not eval) 4) Write code in C++, but only when required to make (2) easy. (Abundant existing code may hinder my goals, and force more C++) 5) Develop a library of unittest methods. __ Yahoo! Canada Toolbar: Search from anywhere on the web, and bookmark your favourite sites. Download it now at http://ca.toolbar.yahoo.com. ___ Cplusplus-sig mailing list Cplusplus-sig@python.org http://mail.python.org/mailman/listinfo/cplusplus-sig
Re: [C++-sig] PyEval_EvalCode
Alan Baljeu wrote: To solve this, I intend to write as much Python as possible, to drive C++ objects, so I won't have to recompile, or restart my environment. (Previous use of python had a slightly different goal: use Python minimally for a dynamic modeling problem) So Python code will consist of interactive and non-interactive scripts. These scripts receive objects, work with them, and return other objects. There are no persistent Python objects. There are probably Python classes designed as temporary wrappers of C++ classes. Steps 1) Embed Python in this C++ plug-in. [Done.] 2) Expose C++ objects (functions and/or data) defined by the plugin to Python. 3) Write code in Python to create and manipulate those objects. (exec, not eval) 4) Write code in C++, but only when required to make (2) easy. (Abundant existing code may hinder my goals, and force more C++) 5) Develop a library of unittest methods. This sounds perfectly reasonable to me, FWIW. An interesting question then is how you embed your interactive Python shell into the application's main event loop. But that's mainly an implementation detail. :-) Regards, Stefan -- ...ich hab' noch einen Koffer in Berlin... ___ Cplusplus-sig mailing list Cplusplus-sig@python.org http://mail.python.org/mailman/listinfo/cplusplus-sig
Re: [C++-sig] PyEval_EvalCode
>This sounds perfectly reasonable to me, FWIW. >An interesting question then is how you embed your interactive Python shell >into the application's main event loop. But that's mainly an implementation >detail. :-) > >Regards, > Stefan Well, rendering is on a separate thread, so no issue there. My plan is: 1) create a console 2) type text into the console 3) ask you guys how to get the interactive Python shell to respond to that text. If there's another option besides a console window, I'm interested. __ Be smarter than spam. See how smart SpamGuard is at giving junk email the boot with the All-new Yahoo! Mail. Click on Options in Mail and switch to New Mail today or register for free at http://mail.yahoo.ca ___ Cplusplus-sig mailing list Cplusplus-sig@python.org http://mail.python.org/mailman/listinfo/cplusplus-sig
Re: [C++-sig] PyEval_EvalCode
on Wed Nov 12 2008, Alan Baljeu wrote: >>This sounds perfectly reasonable to me, FWIW. >>An interesting question then is how you embed your interactive Python shell >>into the > application's main event loop. But that's mainly an implementation detail. :-) >> >>Regards, > > Stefan > > Well, rendering is on a separate thread, so no issue there. My plan is: > 1) create a console > 2) type text into the console > 3) ask you guys how to get the interactive Python shell to respond to that > text. That looks like a question someone on the regular Python (non-C++) list would likely be better at answering. > If there's another option besides a console window, I'm interested. And that one too. -- Dave Abrahams BoostPro Computing http://www.boostpro.com ___ Cplusplus-sig mailing list Cplusplus-sig@python.org http://mail.python.org/mailman/listinfo/cplusplus-sig
[C++-sig] c++ object deleted
Hi all, Is possible in boost::python create a exception when the c++ object is deleted internal, and you try use the python object. Because here I got a core when I try do this. BR -- Renato Araujo Oliveira Filho ___ Cplusplus-sig mailing list Cplusplus-sig@python.org http://mail.python.org/mailman/listinfo/cplusplus-sig
Re: [C++-sig] c++ object deleted
Renato Araujo wrote: Hi all, Is possible in boost::python create a exception when the c++ object is deleted internal, and you try use the python object. Because here I got a core when I try do this. I'm not sure whether it's technically possible, but I do believe this is a bad idea: Exceptions are just the wrong tool to deal with programming errors. Instead, you need to figure out what the expected lifetime of your object is and why it got deleted before. Once you understand this, modify your boost.python wrappers to use the appropriate return-value (or call) policies so this doesn't happen again. Regards, Stefan -- ...ich hab' noch einen Koffer in Berlin... ___ Cplusplus-sig mailing list Cplusplus-sig@python.org http://mail.python.org/mailman/listinfo/cplusplus-sig
Re: [C++-sig] Manage new object return policy (was Re: new to python; old to C++)
David Abrahams wrote: > on Mon Nov 10 2008, Paul Melis wrote: > > >> The FAQ entry on this doesn't really help, so perhaps I'm not using the >> return policy >> correctly or missing something else. The full test code (which is actually >> quite >> small) is attached. >> > > Please reduce it to its absolute minimum. Remove every single thing you > don't need in order to produce the result. If the problem isn't > glaringly obvious to you then, I will help. > Well, I tried reducing in several different ways. The bottom line is that I can't seem to produce this without using the wrapper class (or perhaps I missed the right combination of return policies). Simplest test case (see below for the rest of the files): #!/usr/bin/env python from boost import * class MyCallback(Callback): def __init__(self): Callback.__init__(self) def __call__(self): return Value() cb = MyCallback() r = go(cb) Storing a reference to the Value instance returned in __call__ keeps the instance alive, so the dangling pointer is caused by the Value instance that is returned getting destructed. But this only happens when the instance is passed through go() as its return value. When calling cb directly the Value is not destructed (as I would expect). What I don't understand is why it is destructed when it *is* passed through go(), shouldn't the manage_new_object policy keep it alive? Regards, Paul // classes.h #ifndef CLASSES_H #define CLASSES_H #include class Value { public: Value() { printf("Value::Value()\n"); } Value(const Value& v) { printf("Value::Value(const Value& v)\n"); } ~Value(){ printf("Value::~Value()\n"); } }; class Callback { public: Callback() {} Callback(const Callback& cb){} virtual ~Callback() {} // Returns new Value instance virtual Value* operator()() { return new Value(); } }; Value *go(Callback *cb) { return (*cb)(); }; #endif // boost.cpp // g++ -shared -fPIC -O3 -o boost.so -I/usr/include/python2.5 boost.cpp -lboost_python -lpython2.5 #include #include "classes.h" namespace bp = boost::python; struct CallbackWrap : Callback, bp::wrapper { virtual Value *operator()() { printf("CallbackWrap::operator()\n"); if (bp::override call = this->get_override("__call__")) { printf("Have override for __call__, calling it\n"); return call(); } return Callback::operator()(); } Value *default_call() { printf("CallbackWrap::default_call()\n"); return this->Callback::operator()(); } }; BOOST_PYTHON_MODULE(boost) { bp::class_< Value >("Value"); bp::class_< CallbackWrap, boost::noncopyable >("Callback") .def("__call__", &Callback::operator(), &CallbackWrap::default_call, bp::return_value_policy()); bp::def("go", &go, bp::return_value_policy()); } ___ Cplusplus-sig mailing list Cplusplus-sig@python.org http://mail.python.org/mailman/listinfo/cplusplus-sig
Re: [C++-sig] Manage new object return policy (was Re: new to python; old to C++)
on Wed Nov 12 2008, Paul Melis wrote: > David Abrahams wrote: >> on Mon Nov 10 2008, Paul Melis wrote: >> >> >>> The FAQ entry on this doesn't really help, so perhaps I'm not using the >>> return > policy >>> correctly or missing something else. The full test code (which is actually >>> quite >>> small) is attached. >>> >> >> Please reduce it to its absolute minimum. Remove every single thing you >> don't need in order to produce the result. If the problem isn't >> glaringly obvious to you then, I will help. >> > Well, I tried reducing in several different ways. The bottom line is > that I can't seem to produce this without using the wrapper class (or > perhaps I missed the right combination of return policies). This is a classic example of the FAQ entry. See below. > Simplest test case (see below for the rest of the files): > > #!/usr/bin/env python > from boost import * > > class MyCallback(Callback): > > def __init__(self): > Callback.__init__(self) > > def __call__(self): > return Value() A new C++ Value instance is created here, managed by a Python Value instance. When this function returns, its caller's stack frame will own the only reference to Value. When this is invoked from C++ as an override of a C++ virtual function, its caller is a function in Boost.Python. > > cb = MyCallback() > > r = go(cb) > > > Storing a reference to the Value instance returned in __call__ keeps the > instance alive, so the dangling pointer is caused by the Value instance > that is returned getting destructed. But this only happens when the > instance is passed through go() as its return value. When calling cb > directly the Value is not destructed (as I would expect). What I don't > understand is why it is destructed when it *is* passed through go(), > shouldn't the manage_new_object policy keep it alive? I hope the other things I've written above and below answer the first question. As for the second one, manage_new_object says to manage a new C++ object's lifetime, and the problem you have is that a Python object already owns the C++ object, and that object will go away. I might have a hunch about how to fix some of these problems using a Python WeakPtr, but unfortunately I don't have any time right now to work on it. Best I can do is suggest you open a Trac ticket referencing this thread. > Regards, > Paul > > // classes.h > > #ifndef CLASSES_H > #define CLASSES_H > > #include > > class Value > { > public: > Value() { printf("Value::Value()\n"); } > Value(const Value& v) { printf("Value::Value(const Value& v)\n"); } > ~Value(){ printf("Value::~Value()\n"); } > }; > > class Callback > { > public: > Callback() {} > Callback(const Callback& cb){} > virtual ~Callback() {} > // Returns new Value instance > virtual Value* operator()() { return new Value(); } This one doesn't get executed; it's been overridden by CallbackWrap. > }; > > Value *go(Callback *cb) > { > return (*cb)(); > }; > > #endif > > > // boost.cpp > > // g++ -shared -fPIC -O3 -o boost.so -I/usr/include/python2.5 boost.cpp > -lboost_python -lpython2.5 > > #include > #include "classes.h" > > namespace bp = boost::python; > > struct CallbackWrap : Callback, bp::wrapper > { > virtual Value *operator()() > { > printf("CallbackWrap::operator()\n"); > > if (bp::override call = this->get_override("__call__")) > { A python override has been found here > printf("Have override for __call__, calling it\n"); > return call(); It is invoked in the line above. To return control to you, Boost.Python will reach into the Python Value object to pull out a pointer to the C++ Value object it manages. However, in your case, the reference count on the Python object is 1, and the C++ object will have been deleted by its owner Python object by the time the library returns. > } > > return Callback::operator()(); > } > > Value *default_call() > { > printf("CallbackWrap::default_call()\n"); > return this->Callback::operator()(); > } > }; > > > BOOST_PYTHON_MODULE(boost) > { > bp::class_< Value >("Value"); > > bp::class_< CallbackWrap, boost::noncopyable >("Callback") > .def("__call__", &Callback::operator(), > &CallbackWrap::default_call, > bp::return_value_policy()); > > bp::def("go", &go, bp::return_value_policy()); > } > > > > ___ > Cplusplus-sig mailing list > Cplusplus-sig@python.org > http://mail.python.org/mailman/listinfo/cplusplus-sig > -- Dave Abrahams BoostPro Computing http://www.boostpro.com ___ Cplusplus-sig mailing list Cplusplus-sig@python.org http://mail.python.org/mailman/listinfo/cplusplus-sig
Re: [C++-sig] c++ object deleted
The main problem here is my parent control. My object life is controlled by the parent life time: somethin like that: struct object { object(object *parent) { parent.add_child(this); } ~object() } On Wed, Nov 12, 2008 at 2:14 PM, Stefan Seefeld <[EMAIL PROTECTED]> wrote: > Renato Araujo wrote: >> >> Hi all, >> >> Is possible in boost::python create a exception when the c++ object is >> deleted internal, and you try use the python object. Because here I >> got a core when I try do this. >> > > I'm not sure whether it's technically possible, but I do believe this is a > bad idea: Exceptions are just the wrong tool to deal with programming > errors. Instead, you need to figure out what the expected lifetime of your > object is and why it got deleted before. Once you understand this, modify > your boost.python wrappers to use the appropriate return-value (or call) > policies so this doesn't happen again. > > Regards, > Stefan > > -- > > ...ich hab' noch einen Koffer in Berlin... > > ___ > Cplusplus-sig mailing list > Cplusplus-sig@python.org > http://mail.python.org/mailman/listinfo/cplusplus-sig > -- Renato Araujo Oliveira Filho ___ Cplusplus-sig mailing list Cplusplus-sig@python.org http://mail.python.org/mailman/listinfo/cplusplus-sig