Any Boost.Python equivalent to **keywords?
I would like to construct a class with a **keywords construct: class tclass: def __init__(self, **keywords) for k in kw.keys() self.__dict__[k] = kw[k]
t = tclass(a = 1, b = 2, c = 3) t.a, t.b, t.c 1, 2, 3
I realize that this sort of open-ended Python construct would probably be difficult to generate with templates. I've looked through the test cases in the 1_29_0 distribution and can't find anything to do this. It probably wouldn't be too hard to generate a helper function to turn a **keywords construct into a dictionary and use that to initialize a C++ defined class object, I was just wondering if there was a built in way... Many thanks. -- Matt Giger Lunar Software, Inc. mgiger@lunarsoft.com
Matt Giger <mgiger@lunarsoft.com> writes:
I would like to construct a class with a **keywords construct:
class tclass: def __init__(self, **keywords) for k in kw.keys() self.__dict__[k] = kw[k]
t = tclass(a = 1, b = 2, c = 3) t.a, t.b, t.c 1, 2, 3
I realize that this sort of open-ended Python construct would probably be difficult to generate with templates. I've looked through the test cases in the 1_29_0 distribution and can't find anything to do this.
It probably wouldn't be too hard to generate a helper function to turn a **keywords construct into a dictionary and use that to initialize a C++ defined class object, I was just wondering if there was a built in way...
I have some changes sitting on my disk that will allow you to do this; I'll try to check it in later today. -Dave -- Dave Abrahams Boost Consulting www.boost-consulting.com
Is there any possibility to iterate trough a boost::python::list (or dictionary) from within C++ ? I could not find anything in the documentation. thanks, - harold - -- Live in a world of your own. But always welcome visitors. --
harold fellermann <harold@imb-jena.de> writes:
Is there any possibility to iterate trough a boost::python::list (or dictionary) from within C++ ? I could not find anything in the documentation.
Well, for a list you can call x.attr("__len__")() to get its length and index it. For a dictionary you can call items() and then do the same. However, it would be interesting to make a standard input_iterator that could iterate over the items, e.g.: for ( input_iterator i = begin(some_list_or_dict); i != end(some_list_or_dict); ++i) { whatever(*i); } Nice project for someone who wants to make a contribution. -- Dave Abrahams Boost Consulting www.boost-consulting.com
--- David Abrahams <dave@boost-consulting.com> wrote:
harold fellermann <harold@imb-jena.de> writes:
Is there any possibility to iterate trough a boost::python::list (or dictionary) from within C++ ? I could not find anything in the documentation.
Well, for a list you can call x.attr("__len__")() to get its length and index it.
You can also do this: #include <boost/python/detail/api_placeholder.hpp> int l = boost::python::len(some_list_or_dict);
Nice project for someone who wants to make a contribution.
Expanding api_placeholder.hpp into a comprehensive solution constitutes another nice project for someone wanting to make a contribution. Ralf __________________________________________________ Do you Yahoo!? Yahoo! Tax Center - forms, calculators, tips, more http://taxes.yahoo.com/
"Ralf W. Grosse-Kunstleve" <rwgk@yahoo.com> writes:
You can also do this:
#include <boost/python/detail/api_placeholder.hpp>
int l = boost::python::len(some_list_or_dict);
Nice project for someone who wants to make a contribution.
Expanding api_placeholder.hpp into a comprehensive solution constitutes another nice project for someone wanting to make a contribution.
Absolutely, and I would support that idea. -- Dave Abrahams Boost Consulting www.boost-consulting.com
Hi - I recently experimented with the new "staticmethod" attribute to wrap static class methods. I works beautifully ... great work ! This leads me to ask: is there any existing/planned equally convenient way to wrap static class variables ? I am thinking of something along the lines of struct MyClass { double value1; double value2; } python::class_<MyClass>("MyClass") .def_readwrite("value2", &MyClass::value) .staticvariable("value2"); <<<<<< ????????? so that from python I could simply say MyClass.value2 = 2.0 As always, your help/comments/suggestions are greatly appreciated. -Francois ---------------------------------------------------------------------------- Dr. Jean-Francois OSTIGUY voice: (630) 840-2231 Beam Physics Dept MS220 FAX: (630) 840-6039 Fermi National Accelerator Laboratory email: ostiguy@fnal.gov Batavia IL 60510-0500 WWW:www-ap.fnal.gov/~ostiguy
Francois Ostiguy <ostiguy@fnal.gov> writes:
Hi -
I recently experimented with the new "staticmethod" attribute to wrap static class methods. I works beautifully ... great work !
Thanks go mostly to Nikolay Mladenov, who contributed it.
This leads me to ask: is there any existing/planned equally convenient way to wrap static class variables ?
See http://aspn.activestate.com/ASPN/Mail/Message/1547542, though I am now favoring option 2 at the end of that message over option 1. I don't have a plan to implement it soon unless someone hires me to do it, just because I have a lot on my plate already... but someone else may want to do it.
I am thinking of something along the lines of
struct MyClass { double value1; double value2;
I assume you meant to add a static data member called 'value' here??
}
python::class_<MyClass>("MyClass") .def_readwrite("value2", &MyClass::value) .staticvariable("value2"); <<<<<< ?????????
That syntax would not be neccessary; it would be enough to write: python::class_<MyClass>("MyClass") .def_readwrite("value2", &MyClass::value) ; ...since &MyClass::value is not a data member pointer, but a simple object pointer and thus we can deduce that it should act like a static data member. -- Dave Abrahams Boost Consulting www.boost-consulting.com
David Abrahams <dave@boost-consulting.com> writes:
It probably wouldn't be too hard to generate a helper function to turn a **keywords construct into a dictionary and use that to initialize a C++ defined class object, I was just wondering if there was a built in way...
I have some changes sitting on my disk that will allow you to do this; I'll try to check it in later today.
OK, please check out the latest from CVS. You can find a description of how to use it in libs/python/doc/v2/raw_function.html. -- Dave Abrahams Boost Consulting www.boost-consulting.com
hello,
Is there any possibility to iterate trough a boost::python::list (or dictionary) from within C++ ? I could not find anything in the documentation. Well, for a list you can call x.attr("__len__")() to get its length and index it.
how can I convert the return type list.attr("__len__") from boost::python::api::proxy<boost::python::api::const_attribute_policies> to size_t? will it then be possible to reach the elements of the list via 'list[index]' or how can this be done? thanks, - harold - -- Live in a world of your own. But always welcome visitors. --
harold fellermann wrote:
hello,
Is there any possibility to iterate trough a boost::python::list (or dictionary) from within C++ ? I could not find anything in the documentation.
Well, for a list you can call x.attr("__len__")() to get its length and index it.
how can I convert the return type list.attr("__len__") from boost::python::api::proxy<boost::python::api::const_attribute_policies> to size_t?
As Dave mentioned, you need to use x.attr("__len__")(). Notice the *additional* pair of braces.
will it then be possible to reach the elements of the list via 'list[index]'
Yes. Dirk Gerrits
Dirk Gerrits <dirk@gerrits.homeip.net> writes:
As Dave mentioned, you need to use x.attr("__len__")(). Notice the *additional* pair of braces.
True, but that result is just an 'object'. He needs extract<std::size_t>(x.attr("__len__")()) to get a size_t out of it. -- Dave Abrahams Boost Consulting www.boost-consulting.com
On Dienstag, März 11, 2003, at 04:39 Uhr, David Abrahams wrote:
Dirk Gerrits <dirk@gerrits.homeip.net> writes:
As Dave mentioned, you need to use x.attr("__len__")(). Notice the *additional* pair of braces.
True, but that result is just an 'object'. He needs extract<std::size_t>(x.attr("__len__")()) to get a size_t out of it.
Thank you, this works fine. But I still cannot get along with my stuff... My plan is to insert references to C++ objects within a boost::python::list. The code looks like the following: class X { // ... }; class Y { public: void insert(X &); boost::python::list xlist; }; void Y::insert(X &x) { // do some other things xlist.insert(0,x) } int main() { X x; Y y; y.insert(x); } Unfortunately this little snippet crashes: Program received signal SIGABRT, Aborted. [Switching to Thread 1024 (LWP 26257)] 0x401a6df1 in kill () from /lib/libc.so.6 (gdb) bt #0 0x401a6df1 in kill () from /lib/libc.so.6 #1 0x4008f06d in pthread_kill () from /lib/libpthread.so.0 #2 0x4008f5eb in raise () from /lib/libpthread.so.0 #3 0x401a84d9 in abort () from /lib/libc.so.6 #4 0x4012a5d7 in __cxxabiv1::__terminate(void (*)()) () from /usr/lib/libstdc++.so.5 #5 0x4012a624 in std::terminate() () from /usr/lib/libstdc++.so.5 #6 0x4012a7a6 in __cxa_throw () from /usr/lib/libstdc++.so.5 #7 0x4004df59 in boost::python::throw_error_already_set() () from /usr/local/lib/libboost_python.so.1.29.0 #8 0x080e9fea in boost::python::converter::arg_to_python<Node>::arg_to_python(Node const&) () #9 0x080e8c41 in _object* boost::python::api::object_initializer<false, false>::get<Node>(Node const*, int*) () #10 0x080e777c in boost::python::api::object::object<Node>(Node const&) () #11 0x080e748d in void boost::python::list::insert<Node>(int, Node const&) () #12 0x080e63cf in Network::add_node(Node&) () #13 0x080e2858 in DynamicNetwork::add_node(DynamicNode&) () #14 0x080e1e81 in main () #15 0x401954a2 in __libc_start_main () from /lib/libc.so.6 What am I doing wrong this time? My general ambition is to reimplement some classes originally written in python. So my intention is not to not intrude the underlying C++-classes, but rather to not intrude the overlying python-classes. This is why I need a boost::python::list as a public member of some C++ classes. The references inside the list must be accessible from either python and C++. Do you think this approach is passable with boost::python or is this a misuse of the library? thank you, - harold - -- Live in a world of your own. But always welcome visitors. --
--- harold fellermann <harold@imb-jena.de> wrote:
The code looks like the following:
class X { // ... };
class Y { public: void insert(X &); boost::python::list xlist; };
void Y::insert(X &x) { // do some other things xlist.insert(0,x) }
int main() { X x; Y y; y.insert(x); }
Unfortunately this little snippet crashes:
Of course. You are not initializing the Python interpreter. Are you aware of the difference between "extending" and "embedding"? There is an "embedding" example in the Boost 1.30.0 release candidate that you might want to look at (boost/libs/python/test/embedding.cpp). Most everything else in that directory are "extending" examples. Ralf __________________________________________________ Do you Yahoo!? Yahoo! Web Hosting - establish your business online http://webhosting.yahoo.com
harold fellermann <harold@imb-jena.de> writes:
Thank you, this works fine. But I still cannot get along with my stuff... My plan is to insert references to C++ objects within a boost::python::list. The code looks like the following:
class X { // ... };
class Y { public: void insert(X &); boost::python::list xlist; };
void Y::insert(X &x) { // do some other things xlist.insert(0,x) }
int main() { X x; Y y; y.insert(x); }
Unfortunately this little snippet crashes:
You're not being (completely) honest with us ;-) There's a class called "Node" somewhere which you haven't told us about. Aside from not initializing the interpreter, it looks like you have not exposed class Node to python. That's what's causing the exception throw you see in the stack backtrace. -- Dave Abrahams Boost Consulting www.boost-consulting.com
On Mittwoch, März 12, 2003, at 06:16 Uhr, David Abrahams wrote:
harold fellermann <harold@imb-jena.de> writes:
Thank you, this works fine. But I still cannot get along with my stuff... You're not being (completely) honest with us ;-) There's a class called "Node" somewhere which you haven't told us about.
True, the X and Y-classes where to much of abstraction ... so here is the code that troubles me, and I hope I won't cut out anything essential this time. class Node { unsigned id; Network *net; // some stupid data that has nothing to do with python nor boost... }; class Network : public Node { public: virtual size_t add_node(Node &); python::list nodes; private: BGL_GRAPH graph; // BGL_GRAPH is a typedef defined somewhere other }; My implementation of Network::add_node is this: size_t Network::add_node(Node &node) { // get new BGL-node size_t id = add_vertex(graph); node.id = id; node.net = this; // insert the node in nodelist nodes.insert(0,node); return id; } and here is how I wrapped those lines: BOOST_PYTHON_MODULE(network) { class_<Node>("Node") .def_readonly("net_id", &Node::id) // [...] ; class_<Network, bases<Node> >("Network") .def_readonly("nodes", &Network::nodes) .def("addNode", &Network::add_node, with_custodian_and_ward<1,2>()) // [...] ; } I don't know whether I still need 'with_custodian_and_ward' here (historical reasons). This seems to work if compiled as a python module. At least, my little test program from network import * net = Network() node = Node() net.addNode(node) print net.nodes doesn't complain about anything. Using the same classes from C++ causes trouble. Here is my main function (forgot to copy the Py_Initialize last time, so this is not the point). int main() { Py_Initialize(); Network net; Node node; net.add_node(node); cout << "node added." << endl; return 0; } The code fails in net.add_node(node). Here once again is my debugger's backtrace (In my last posting, things where slightly more complex, but I could reduce the erroneous behaviour to the lines above): (gdb) run Starting program: /home/tsb/harold/cpp_source/test [New Thread 1024 (LWP 27184)] Program received signal SIGABRT, Aborted. [Switching to Thread 1024 (LWP 27184)] 0x401a6df1 in kill () from /lib/libc.so.6 (gdb) bt #0 0x401a6df1 in kill () from /lib/libc.so.6 #1 0x4008f06d in pthread_kill () from /lib/libpthread.so.0 #2 0x4008f5eb in raise () from /lib/libpthread.so.0 #3 0x401a84d9 in abort () from /lib/libc.so.6 #4 0x4012a5d7 in __cxxabiv1::__terminate(void (*)()) () from /usr/lib/libstdc++.so.5 #5 0x4012a624 in std::terminate() () from /usr/lib/libstdc++.so.5 #6 0x4012a7a6 in __cxa_throw () from /usr/lib/libstdc++.so.5 #7 0x4004df59 in boost::python::throw_error_already_set() () from /usr/local/lib/libboost_python.so.1.29.0 #8 0x080e9cb4 in boost::python::converter::arg_to_python<Node>::arg_to_python(Node const&) () #9 0x080e8679 in _object* boost::python::api::object_initializer<false, false>::get<Node>(Node const*, int*) () #10 0x080e7542 in boost::python::api::object::object<Node>(Node const&) () #11 0x080e6458 in Network::add_node(Node&) () #12 0x080e1e20 in main () #13 0x401954a2 in __libc_start_main () from /lib/libc.so.6 Why does the code run in python but not in C++? There must be a logical error I made, but I can't see it. Thank you very much for your help. By the way: as you can guess, I'm a newbie to boost::python (also with absolutely no knowledge about the Python-C-API). I think that there is a little gap between the short tutorial introduction and the rather technical reference. Is there any additional documentation that could narrow this gap? If not, I'd like to enhance the tutorial to boost::python, as soon as I look through the library, so that newbies like me have no need to steel your time with their questions. Is this a deal? - harold - -- Always remember that you are unique; just like everyone else. --
hi. As you might know in the meanwhile, I want to insert references (not instances) of C++ objects into a boost::python::list. I thought that calling CPPObject cpp_obj; list.insert(0,handle<>(borrowed(cpp_obj))) would do the thing. According to the documentation I need to inherit from PyObject: class CPPObject : public PyObject { // [...] }; and as soon as I do this, my code is compiled without error, but failed in the constructor of CPPObject. As stated in the Python/C-API, "you never declare an automatic or static variable of type PyObject, only pointer variables of type PyObject* can be declared." So how can the references be stored? - harold - -- "I know what I believe. I will continue to articulate what I believe and what I believe - I believe what I believe is right." -- George W. Bushman
--- harold fellermann <harold@imb-jena.de> wrote:
class CPPObject : public PyObject { // [...] };
and as soon as I do this, my code is compiled without error, but failed in the constructor of CPPObject. As stated in the Python/C-API, "you never declare an automatic or static variable of type PyObject, only pointer variables of type PyObject* can be declared." So how can the references be stored?
PyObjects are C objects. They have no constructor and destructor etc. Instead you have to use a combination of Python C API functions to emulate what is normally done by C++ constructors and destructors. If you use Boost.Python's class_<> template all this will be done for you automatically. This is pretty much the essence of Boost.Python. Please study the fine tutorial to learn more about class_<>. You can create wrapped instances of your C++ objects in various ways. The simplest method is to copy an existing object into the newly created wrapped object. But you can also copy references/pointers to existing C++ objects. This is more involved because you have to think about and correctly deal with lifetime issues. This is nicely explained in the tutorial under "Call Policies." Ralf __________________________________________________ Do you Yahoo!? Yahoo! Web Hosting - establish your business online http://webhosting.yahoo.com
harold fellermann <harold@imb-jena.de> writes:
hi.
As you might know in the meanwhile, I want to insert references (not instances) of C++ objects into a boost::python::list. I thought that calling
CPPObject cpp_obj; list.insert(0,handle<>(borrowed(cpp_obj)))
would do the thing. According to the documentation I need to inherit from PyObject:
class CPPObject : public PyObject { // [...] };
and as soon as I do this, my code is compiled without error, but failed in the constructor of CPPObject. As stated in the Python/C-API, "you never declare an automatic or static variable of type PyObject, only pointer variables of type PyObject* can be declared." So how can the references be stored?
First, please do what Ralf said and read the fine tutorial front-to-back before proceeding, or trying anything I've said below. You need to get a better sense of how the library works in order to understand any advice we can give here. One way, but not neccessarily a safe one, to get a Python object into your list which wraps a reference to a C++ object, is list.insert(0, boost::ref(cpp_obj)); I say "not neccessarily safe" because there is nothing here to help manage the lifetime of the C++ object properly; if it is destroyed before the last Python reference you could crash the program with Python code. Since you say: "My general ambition is to reimplement some classes originally written in python. So my intention is not to not intrude the underlying C++-classes, but rather to not intrude the overlying python-classes" I would recommend that you manage all your C++ objects with boost::shared_ptr<>. This is probably the most-foolproof way of getting lifetime issues sorted out, since boost::shared_ptr magically takes care of many issues; see http://article.gmane.org/gmane.comp.python.c++/2530/match=shared+ptr -- Dave Abrahams Boost Consulting www.boost-consulting.com
hi.
As you might know in the meanwhile, I want to insert references (not instances) of C++ objects into a boost::python::list. I thought that calling
CPPObject cpp_obj; list.insert(0,handle<>(borrowed(cpp_obj))) First, please do what Ralf said and read the fine tutorial front-to-back beforte proceeding, or trying anything I've said below. You need to get a better sense of how the library works in order to understand any advice we can give here.
I did that, you were right. I also did some reading about extending and embedding python. It's getting clearer now, but there is still one questian unsolved (see below).
One way, but not neccessarily a safe one, to get a Python object into your list which wraps a reference to a C++ object, is
list.insert(0, boost::ref(cpp_obj));
I say "not neccessarily safe" because there is nothing here to help manage the lifetime of the C++ object properly; if it is destroyed before the last Python reference you could crash the program with Python code.
This works. I use with_custodian_and_ward to bind the lifetime of cpp_obj to the object that inserts it into its list of references. There encountert no lifetime problem when using the classes as python extensions. However, trying to use my classes with embedded python still troubles me. The thing I don't understand is the following: when I insert a cpp_obj in python, I deal with a python::object because of the wrapper classes, which works fine. But when I use the same (unwrapped) classes for embedded python, any attempt to insert ref(cpp_obj) into my python::list still dumps. What is the reason therefore? Is there a concept I haven't understood yet? Thank you for the patience! - harold - -- "2x2 = grün" -- Heinz von Foerster
harold fellermann <harold@imb-jena.de> writes:
One way, but not neccessarily a safe one, to get a Python object into your list which wraps a reference to a C++ object, is
list.insert(0, boost::ref(cpp_obj));
I say "not neccessarily safe" because there is nothing here to help manage the lifetime of the C++ object properly; if it is destroyed before the last Python reference you could crash the program with Python code.
This works. I use with_custodian_and_ward to bind the lifetime of cpp_obj to the object that inserts it into its list of references.
That doesn't work. with_custodian_and_ward only binds the lifetime of Python objects. If the C++ object is held by a corresponding Python object via raw pointer or reference (as with boost::ref(cpp_obj)), it will not do anything to handle the problem I mentioned above.
There encountert no lifetime problem when using the classes as python extensions.
I think you were lucky.
However, trying to use my classes with embedded python still troubles me. The thing I don't understand is the following: when I insert a cpp_obj in python, I deal with a python::object because of the wrapper classes, which works fine. But when I use the same (unwrapped) classes for embedded python, any attempt to insert ref(cpp_obj) into my python::list still dumps. What is the reason therefore? Is there a concept I haven't understood yet?
You haven't explained the problem well enough to know. Code (preferably minimal) helps. Minimizing the code may also teach you where you went wrong. -- Dave Abrahams Boost Consulting www.boost-consulting.com
participants (6)
-
David Abrahams -
Dirk Gerrits -
Francois Ostiguy -
harold fellermann -
Matt Giger -
Ralf W. Grosse-Kunstleve