[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