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

David Abrahams dave at boost-consulting.com
Sun Aug 14 21:36:46 CEST 2005


"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?

> 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());


> 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.

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

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

HTH,
-- 
Dave Abrahams
Boost Consulting
www.boost-consulting.com




More information about the Cplusplus-sig mailing list