Deriving Built-In Classes in Python
The struct member module, as useful as it is, has many limitations. The most obvious one is that it only supports a small number of data types and is not generally extensible. Since many Motif call data structures contain members that are structures, pointers, unions, enums, and even arrays, the straight forward approach would not be able to give adequate coverage and most call data structures would have had to be tediously bound to by hand.
Symbolic constants presented a different set of problems. Storing a set of symbolic constants as simple variables inside a module is subject to the user accidentally changing the value of what was intended to be a constant. It was also thought that users would expect a more symbolic treatment of symbolic constants from an interpreted environment. For example,
>>> print Xm.ALIGNMENT_CENTER 1by itself is not all that bad, however it is much more likely that while developing or debugging a real application you would see something more like
>>> push_button.alignment = Xm.ALIGNMENT_CENTER ... >>> print push_button.alignment 1Clearly, this does not tell you much about the alignment of the push button unless you happen to know that
Xm.ALIGNMENT_CENTER
has a value of 1. Something much more self explanatory would be
>>> print push_button.alignment Xm.Alignment.CenterIt became obvious that a more generic solution to the problem of symbolic constants was in order.
More recently I have been involved in binding a very large C++ class library to Python. Again, the initial results were very promising but there were problems. The requirements for this set of bindings were very similar to those for the Xt bindings. A user who was familiar with the C++ class library should be able to apply their familiarity to the Python implementation. The technique that was chosen to implement the bindings was in many ways similar to the way the Xt bindings were implemented. One built-in object was implemented to represent instances of the class library and a second built-in object was implemented to represent the classes in the class library. The instance object needed to contain a reference to the object that it was to represent and a reference to its class object. Each class object contained a reference to its base class object and the bindings to all of the methods defined on the class but not already defined by any of its base classes. This provided a simple inheritance mechanism which made it unnecessary to re-implement bindings that had already been implemented.
The fundamental problem with this implementation was its inability to allow the derivation, in Python, of new classes from those in the C++ class library. Since, unlike Xt, the C++ library was designed with derivation of new classes as the intended way of building applications, it was essential that a solution be found. The first attempt was straightforward. When binding to a class that has virtual functions, a derived class is created that implements the virtual function. Each virtual function was implemented by adding a Python object attribute to reference the Python function that was to act as the implementation of the virtual function. The binding to this derived class supports methods for setting and getting this attribute. The overall effect is very similar to a widget callback function in Xt. Then, to give the appearance of the ability to derive from the class binding, a Python class is created to act as a wrapper for the built-in class. The __init__
function of the wrapper class is responsible for checking if a virtual function was implemented in a derived class and for setting the callback functions appropriately. There are two obvious problems with this approach:
The remainder of this paper discusses the approach that was taken to solve the problems that were mentioned above and to support the derivation of built-in classes in Python.
Generated with CERN WebMaker