[C++-sig] Mapping an entire data structure over to a single Python instance. (Newbie question)

g.j.murphy at sageserpent.com g.j.murphy at sageserpent.com
Mon Aug 15 10:34:07 CEST 2005



"Dave Abrahams" <dave at boost-consulting.com> writes:
> "Gerard Murphy" <g.j.murphy at sageserpent.com> writes:
> 
> > 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.
> 
> Is that an important feature of the system?

It's a 'very nice to have' - but I could fallback to just treating all maps
as being, well, dictionaries in Python.  :-)

Something I didn't mention in the original post is that I would like to add
certain methods onto certain of these classes, and that the client code on the
Python side would know in advance what set of methods the instances
would be expected to possess: these objects would be passed over to Python in
sets where each member of the set would respond to the same set of method calls.

In effect I'm saying that if objects 'A' and 'B' both possess the attributes
'foo' and 'bar', then they would acquire a method 'doSomethingImportantInvolvingFooAndBar'.

Object 'C' on the other hand that possesses property 'baz' acquires another method, say
'shutdownReactorAfterInternalDialogueWithBaz'.  ;-)

'A' and 'B' would be passed together to one Python function, 'C' would be passed to another.

All three of these objects might have other attributes that could be optionally accessible
on the Python side, but are not vital for the correct operation of the system.



> 
> > 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);
> 
> No, that won't work.
> 
> What you can do is use Python's metaclass API.
> http://gnosis.cx/publish/programming/metaclass_1.html
> 
> Export your C++ DataStructure class once.  
> 
> 
>        object data_structure
>            = class_<DataStructure>( ... )
>                 ...
>                 ;
> 
>        
> Then get its metaclass:
> 
>      object meta = object(
>           handle<>(
>               borrowed(data_structure.ptr()->ob_type)
>           )
>      );
> 
> Now you can manufacture distinct subclasses on-the-fly:
> 
>     object new_subclass = meta(
>         "name-of-subclass", python::make_tuple(data_structure),
>         dict());
> 


Excellent!



> 
> > 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.
> 
> I suggest you don't do that either.  It would be better to implement a
> __getattr__ method in your exported DataStructure.
> 
>        object getattr(DataStructure& ds, std::string name)
>        {
>            return object( ...lookup name in ds... );
>        }
> 
>        object data_structure
>            = class_<DataStructure>( ... )
>                 .def("__getattr__", getattr)
>                 ;
> 
> For this you'll need to export class_<AbstractValue> and
> class_<ConcreteValue<T> > for each ConcreteValue<T> you are using.


Ah - yes, that's much better.



> 
> > 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.
> 
> Doing it with add_property is going to be a bear.  Why would you want
> to do that?


As a Python novice, I had automatically assumed that properties were
the only form of abstraction available on instance variable access (I had C# in mind).

Now that you've introduced me to '__getattr__' and the like, I've seen the light. :-)



> 
> > *** 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?  
> 
> Nope
> 

No problem, that's now obsolete in the light of using the metaclass object to produce more classes.


Many thanks,

Gerard









More information about the Cplusplus-sig mailing list