Mapping an entire data structure over to a single Python instance. (Newbie question)
Hello, I'm evaluating the potential use of the Boost.Python facilities. I've looked though the tutorial and *some* of the detailed API documentation available from www.boost.org, and so far it all looks very promising. However... I have a rather strange use planned for the C++ to Python interface that isn't covered by the tutorial. The detailed API documentation doesn't seem to answer my question either; so I'd like to put it to the mailing list, as I'm sure that this idea has already occurred to somebody in the past. *** Background *** What I'd like to do is map an entire data structure over to a single Python instance, so that individual properties of the Python object would correspond to parts of the data structure. To add spice to this, the data structure is in a sense weakly typed: different parts of it are composed out of very different C++ types. The data structure is dynamically built (otherwise there wouldn't be in issue as I could map a C-style structure or getter/setter class over to a Python class using the techniques described in the tutorial). I'll make this a little bit more concrete:- 1. I have what is effectively a weakly typed wrapper around a set of different C++ types using external polymorphism:- class AbstractValue { public: ~virtual AbstractValue(); }; template <typename StrongType> class ConcreteValue: public AbstractValue { public: // Use compiler-generated destructor. ConcreteValue(const StrongType &valueRepresentation): _valueRepresentation(valueRepresentation) StrongType _valueRepresentation; }; Instances of these make their way into a map:- typedef std::map<std::string, boost::shared_ptr<AbstractValue> > DataStructure; 2. Various things in the system populate these maps in different ways, so that from one map instance to another, not only do the associated values change, but so do the number of associations, the keys and the actual types of the associated values. However, lots of these maps share the same common structure in terms of numbers of associations, keys and associated types. These could be thought of as instances of several classes, where each class captures the commonality of structure. These classes effectively come into being as the system runs: they cannot be defined at compile time as conventional C++ classes. No, I can't just write the entire system in Smalltalk (or Python for that matter) ... :-) 3. I'd like to expose these conceptual classes to Python, mapping over these instances of 'DataStructure' mentioned above to Python objects - but with the Python class changing depending on what instance of 'DataStructure' is being mapped. The classes of the Python objects would be dynamically created by construction of a 'class_' object:- // Somewhere this line will be repeatedly executed... boost::python::class_<DataStructure> classObject(name); I'm assuming that although the class_ object will be destroyed at each repetition, the corresponding Python class lives on afterwards. It isn't a problem if this is not the case, as I could always manage these objects in a long-lived container or on the heap or whatever. What I intend to do is to dynamically add properties to 'classObject' that use the name of the property to fetch the appropriate associated value from the map. This would be done once per repetition, so that each repetition would create a brand new Python class. To be a bit more specific, I want to call 'classObject.add_property()' with an application of boost::bind to a template function instantiation that takes a name, looks up the associated value in the map, dynamically casts to the template type parameter and returns the value. I can ask an exemplar map to walk itself so that on behalf of a set of maps sharing the same common structure, it will populate a single class object with the appropriate properties. *** Now for the questions *** OK, that's what I want to do ... but can I do the following first:- i) Can I construct more than one instance of 'class_<DataStructure>' using lots of different names as arguments at each construction call? I get the impression from the documentation that each template instantiation of 'class_ <X>' for a given X might well be a singleton class in terms of usage - only one constructed instance per class template instantiation, if you know what I mean! ii) If I *can* have lots of instances of 'class_<DataStructure>', how does the framework know how to map instances of 'DataStructure' to the appropriate Python class - this seems to be implicitly done rather than explictly done. What I'm driving at here is taking an *existing* instance of DataStructure and wrapping it up as a 'boost::python::object' whose Python type is one of these dynamically constructed classes. This is in contrast to using the 'class_<DataStructure>' object to create the instance of 'boost::python::object' - I would definitely like to avoid doing this if possible, although I appreciate that it is usually the obvious way to go. NOTE: I'm assuming that the properties can be defined using *any* function object that would take an instance of 'DataStructure' and return an appropriately typed value - I am planning on using 'boost::bind' and an appropriate trampoline template function to do this. In the meantime, I'll have a longer trawl through the API documentation and perhaps the implementation source, but I'd appreciate any help from old hands to shorten the process. Many thanks in advance, Gerard
participants (1)
-
Gerard Murphy