diff options
Diffstat (limited to 'ExtensionClass.stx')
-rw-r--r-- | ExtensionClass.stx | 714 |
1 files changed, 0 insertions, 714 deletions
diff --git a/ExtensionClass.stx b/ExtensionClass.stx deleted file mode 100644 index cab7e46b..00000000 --- a/ExtensionClass.stx +++ /dev/null @@ -1,714 +0,0 @@ -Extension Classes, Python Extension Types Become Classes - - Jim Fulton, Digital Creations, Inc. - jim@digicool.com - - "Copyright (C) 1996-1998, Digital Creations":COPYRIGHT.html. - - Abstract - - A lightweight mechanism has been developed for making Python - extension types more class-like. Classes can be developed in an - extension language, such as C or C++, and these classes can be - treated like other python classes: - - - They can be sub-classed in python, - - - They provide access to method documentation strings, and - - - They can be used to directly create new instances. - - An example class shows how extension classes are implemented and how - they differ from extension types. - - Extension classes provide additional extensions to class and - instance semantics, including: - - - A protocol for accessing subobjects "in the context of" their - containers. This is used to implement custom method types - and "environmental acquisition":Acquisition.html. - - - A protocol for overriding method call semantics. This is used - to implement "synchonized" classes and could be used to - implement argument type checking. - - - A protocol for class initialization that supports execution of a - special '__class_init__' method after a class has been - initialized. - - Extension classes illustrate how the Python class mechanism can be - extended and may provide a basis for improved or specialized class - models. - - Releases - - To find out what's changed in this release, - see the "release notes":release.html. - - Problem - - Currently, Python provides two ways of defining new kinds of objects: - - - Python classes - - - Extension types - - Each approach has it's strengths. Extension types provide much greater - control to the programmer and, generally, better performance. Because - extension types are written in C, the programmer has greater access to - external resources. (Note that Python's use of the term type has - little to do with the notion of type as a formal specification.) - - Classes provide a higher level of abstraction and are generally much - easier to develop. Classes provide full inheritance support, while - support for inheritance when developing extension types is very - limited. Classes provide run-time meta-data, such as method documentation - strings, that are useful for documentation and discovery. Classes - act as factories for creating instances, while separate functions - must be provided to create instances of types. - - It would be useful to combine the features of the two approaches. It - would be useful to be able to have better support for inheritance for - types, or to be able to subclass from types in Python. It would be - useful to be able to have class-like meta-data support for types and - the ability to construct instances directly from types. - - Our software is developed in Python. When necessary, we convert - debugged Python routines and classes to C for improved - performance. In most cases, a small number of methods in a class - is responsible for most of the computation. It should be possible - to convert only these methods to C, while leaving the other method - in Python. A natural way to approach this is to create a base - class in C that contains only the performance-critical aspects of - a class' implementation and mix this base class into a Python - class. - - We have need, in a number of projects, for semantics that are - slightly different than the usual class and instance semantics, - yet we don't want to do most of our development in C. For - example, we have developed a persistence mechanism [1] that - redefines '__getattr__' and '__setattr__' to take storage-related - actions when object state is accessed or modified. We want to be - able to take certain actions on *every* attribute reference, but - for python class instances, '__getattr__' is only called when - attribute lookup fails by normal means. - - As another example, we would like to have greater control over how - methods are bound. Currently, when accessing a class - instance attribute, the attribute value is bound together with the - instance in a method object *if and only if* the attribute value is a - python function. For some applications, we might also want to be - able to bind extension functions, or other types of callable - objects, such as HTML document templates [2]. Furthermore, - we might want to have greater control over how objects are bound. - For example, we might want to bind instances and callable objects - with special method objects that assure that no more than one thread - accesses the object or method at one time. - - We can provide these special semantics in extension types, but we - wish to provide them for classes developed in Python. - - Background - - At the first Python Workshop, Don Beaudry presented work [3] done - at V.I. Corp to integrate Python with C++ frameworks. This system - provided a number of important features, including: - - - Definition of extension types that provide class-like meta-data - and that can be called to create instances. - - - Ability to subclass in python from C types. - - - Ability to define classes in python who's data are stored as - C structures rather than in dictionaries to better interface to - C and C++ libraries, and for better performance. - - - Less dynamic data structures. In particular, the data structure - for a class is declared during class definition. - - - Support for enumeration types. - - This work was not released, initially. - - Shortly after the workshop, changes were made to Python to support - the sub-classing features described in [3]. These changes were not - documented until the fourth Python Workshop [4]. - - At the third Python workshop, I presented some work I had done on - generating module documentation for extension types. Based on the - discussion at this workshop, I developed a meta-type proposal [5]. - This meta-type proposal was for an object that simply stored - meta-information for a type, for the purpose of generating module - documentation. - - In the summer of 1996, Don Beaudry released the system described in - [3] under the name MESS [6]. MESS addresses a number of needs but - has a few drawbacks: - - - Only single inheritance is supported. - - - The mechanisms for defining MESS extension types is very different - from and more complicated than the standard Python type creation - mechanism. - - - Defining MESS types requires the use of an extensive C - applications programming interface. This presents problems for - configuring dynamically-loaded extension modules unless the MESS - library is linked into the Python interpreter. - - - Because the system tries to do a number of different things, it is - fairly large, about 15,000 lines. - - - There is very little documentation, especially for the C - programming interface. - - - The system is a work in progress, with a number of outstanding - bugs. - - As MESS matures, we expect most of these problems to be addressed. - - Extension Classes - - To meet short term needs for a C-based persistence mechanism [1], an - extension class module was developed using the mechanism described - in [4] and building on ideas from MESS [6]. The extension class module - recasts extension types as "extension classes" by seeking to - eliminate, or at least reduce semantic differences between types and - classes. The module was designed to meet the following goal: - - - Provide class-like behavior for extension types, including - interfaces for meta information and for constructing instances. - - - Support sub-classing in Python from extension classes, with support - for multiple inheritance. - - - Provide a small hardened implementation that can be used for - current products. - - - Provide a mechanism that requires minimal modification to existing - extension types. - - - Provide a basis for research on alternative semantics for classes - and inheritance. - - **Note:** I use *non-standard* terminology here. By standard - *python* terminology, only standard python classes can be called - classes. ExtensionClass "classes" are technically just "types" - that happen to swim, walk and quack like python classes. - - Base extension classes and extension subclasses - - Base extension classes are implemented in C. Extension subclasses - are implemented in Python and inherit, directly or indirectly from - one or more base extension classes. An extension subclass may - inherit from base extension classes, extension subclasses, and - ordinary python classes. The usual inheritance order rules - apply. Currently, extension subclasses must conform to the - following two rules: - - - The first super class listed in the class statement defining an - extension subclass must be either a base extension class or an - extension subclass. This restriction will be removed in - Python-1.5. - - - At most one base extension direct or indirect super class may - define C data members. If an extension subclass inherits from - multiple base extension classes, then all but one must be mix-in - classes that provide extension methods but no data. - - Meta Information - - Like standard python classes, extension classes have the following - attributes containing meta-data: - - '__doc__' -- a documentation string for the class, - - '__name__' -- the class name, - - '__bases__' -- a sequence of base classes, - - '__dict__' -- a class dictionary, and - - '__module__' -- the name of the module in which the class was - defined. - - The class dictionary provides access to unbound methods and their - documentation strings, including extension methods and special - methods, such as methods that implement sequence and numeric - protocols. Unbound methods can be called with instance first - arguments. - - Subclass instance data - - Extension subclass instances have instance dictionaries, just - like Python class instances do. When fetching attribute values, - extension class instances will first try to obtain data from the - base extension class data structure, then from the instance - dictionary, then from the class dictionary, and finally from base - classes. When setting attributes, extension classes first attempt - to use extension base class attribute setting operations, and if - these fail, then data are placed in the instance dictionary. - - Implementing base extension classes - - A base extension class is implemented in much the same way that an - extension type is implemented, except: - - - The include file, 'ExtensionClass.h', must be included. - - - The type structure is declared to be of type 'PyExtensionClass', rather - than of type 'PyTypeObject'. - - - The type structure has an additional member that must be defined - after the documentation string. This extra member is a method chain - ('PyMethodChain') containing a linked list of method definition - ('PyMethodDef') lists. Method chains can be used to implement - method inheritance in C. Most extensions don't use method chains, - but simply define method lists, which are null-terminated arrays - of method definitions. A macro, 'METHOD_CHAIN' is defined in - 'ExtensionClass.h' that converts a method list to a method chain. - (See the example below.) - - - Module functions that create new instances must be replaced by - '__init__' methods that initialize, but does not create storage for - instances. - - - The extension class must be initialized and exported to the module - with:: - - PyExtensionClass_Export(d,"name",type); - - where 'name' is the module name and 'type' is the extension class - type object. - - Attribute lookup - - Attribute lookup is performed by calling the base extension class - 'getattr' operation for the base extension class that includes C - data, or for the first base extension class, if none of the base - extension classes include C data. 'ExtensionClass.h' defines a - macro 'Py_FindAttrString' that can be used to find an object's - attributes that are stored in the object's instance dictionary or - in the object's class or base classes:: - - v = Py_FindAttrString(self,name); - - where 'name' is a C string containing the attribute name. - - In addition, a macro is provided that replaces 'Py_FindMethod' - calls with logic to perform the same sort of lookup that is - provided by 'Py_FindAttrString'. - - If an attribute name is contained in a Python string object, - rather than a C string object, then the macro 'Py_FindAttr' should - be used to look up an attribute value. - - Linking - - The extension class mechanism was designed to be useful with - dynamically linked extension modules. Modules that implement - extension classes do not have to be linked against an extension - class library. The macro 'PyExtensionClass_Export' imports the - 'ExtensionClass' module and uses objects imported from this module - to initialize an extension class with necessary behavior. - - Example: MultiMapping objects - - An "example":MultiMapping.html, is provided that illustrates the - changes needed to convert an existing type to an ExtensionClass. - - Implementing base extension class constructors - - Some care should be taken when implementing or overriding base - class constructors. When a Python class overrides a base class - constructor and fails to call the base class constructor, a - program using the class may fail, but it will not crash the - interpreter. On the other hand, an extension subclass that - overrides a constructor in an extension base class must call the - extension base class constructor or risk crashing the interpreter. - This is because the base class constructor may set C pointers that, - if not set properly, will cause the interpreter to crash when - accessed. This is the case with the 'MultiMapping' extension base - class shown in the example above. - - If no base class constructor is provided, extension class instance - memory will be initialized to 0. It is a good idea to design - extension base classes so that instance methods check for - uninitialized memory and perform initialialization if necessary. - This was not done above to simplify the example. - - Overriding methods inherited from Python base classes - - A problem occurs when trying to overide methods inherited from - Python base classes. Consider the following example:: - - from ExtensionClass import Base - - class Spam: - - def __init__(self, name): - self.name=name - - class ECSpam(Base, Spam): - - def __init__(self, name, favorite_color): - Spam.__init__(self,name) - self.favorite_color=favorite_color - - This implementation will fail when an 'ECSpam' object is - instantiated. The problem is that 'ECSpam.__init__' calls - 'Spam.__init__', and 'Spam.__init__' can only be called with a - Python instance (an object of type '"instance"') as the first - argument. The first argument passed to 'Spam.__init__' will be an - 'ECSpam' instance (an object of type 'ECSPam'). - - To overcome this problem, extension classes provide a class method - 'inheritedAttribute' that can be used to obtain an inherited - attribute that is suitable for calling with an extension class - instance. Using the 'inheritedAttribute' method, the above - example can be rewritten as:: - - from ExtensionClass import Base - - class Spam: - - def __init__(self, name): - self.name=name - - class ECSpam(Base, Spam): - - def __init__(self, name, favorite_color): - ECSpam.inheritedAttribute('__init__')(self,name) - self.favorite_color=favorite_color - - This isn't as pretty but does provide the desired result. - - New class and instance semantics - - Context Wrapping - - It is sometimes useful to be able to wrap up an object together - with a containing object. I call this "context wrapping" - because an object is accessed in the context of the object it is - accessed through. - - We have found many applications for this, including: - - - User-defined method objects, - - - "Acquisition":Acquisition.html, and - - - Computed attributes - - User-defined method objects - - Python classes wrap Python function attributes into methods. When a - class has a function attribute that is accessed as an instance - attribute, a method object is created and returned that contains - references to the original function and instance. When the method - is called, the original function is called with the instance as the - first argument followed by any arguments passed to the method. - - Extension classes provide a similar mechanism for attributes that - are Python functions or inherited extension functions. In - addition, if an extension class attribute is an instance of an - extension class that defines an '__of__' method, then when the - attribute is accessed through an instance, it's '__of__' method - will be called to create a bound method. - - Consider the following example:: - - import ExtensionClass - - class CustomMethod(ExtensionClass.Base): - - def __call__(self,ob): - print 'a %s was called' % ob.__class__.__name__ - - class wrapper: - - def __init__(self,m,o): self.meth, self.ob=m,o - - def __call__(self): self.meth(self.ob) - - def __of__(self,o): return self.wrapper(self,o) - - class bar(ExtensionClass.Base): - hi=CustomMethod() - - x=bar() - hi=x.hi() - - Note that 'ExtensionClass.Base' is a base extension class that - provides very basic ExtensionClass behavior. - - When run, this program outputs: 'a bar was called'. - - Computed Attributes - - It is not uncommon to wish to expose information via the - attribute interface without affecting implementation data - structures. One can use a custom '__getattr__' method to - implement computed attributes, however, this can be a bit - cumbersome and can interfere with other uses of '__getattr__', - such as for persistence. - - The '__of__' protocol provides a convenient way to implement - computed attributes. First, we define a ComputedAttribute - class. a ComputedAttribute is constructed with a function to - be used to compute an attribute, and calls the function when - it's '__of__' method is called: - - import ExtensionClass - - class ComputedAttribute(ExtensionClass.Base): - - def __init__(self, func): self.func=func - - def __of__(self, parent): return self.func(parent) - - Then we can use this class to create computed attributes. In the - example below, we create a computed attribute, 'radius': - - from math import sqrt - - class Point(ExtensionClass.Base): - - def __init__(self, x, y): self.x, self.y = x, y - - radius=ComputedAttribute(lambda self: sqrt(self.x**2+self.y**2)) - - which we can use just like an ordinary attribute: - - p=Point(2,2) - print p.radius - - Overriding method calls - - Normally, when a method is called, the function wrapped by the - method is called directly by the method. In some cases, it is - useful for user-defined logic to participate in the actual - function call. Extension classes introduce a new protocol that - provides extension classes greater control over how their - methods are called. If an extension class defines a special - method, '__call_method__', then this method will be called to - call the functions (or other callable object) wrapped by the - method. The method. '__call_method__' should provide the same - interface as provided by the Python builtin 'apply' function. - - For example, consider the expression: 'x.meth(arg1, arg2)'. The - expression is evaluated by first computing a method object that - wraps 'x' and the attribute of 'x' stored under the name 'meth'. - Assuming that 'x' has a '__call_method__' method defined, then - the '__call_method__' method of 'x' will be called with two - arguments, the attribute of 'x' stored under the name 'meth', - and a tuple containing 'x', 'arg1', and 'arg2'. - - To see how this feature may be used, see the Python module, - 'Syn.py', which is included in the ExtensionClass distribution. - This module provides a mix-in class that provides Java-like - "synchonized" classes that limit access to their methods to one - thread at a time. - - An interesting application of this mechanism would be to - implement interface checking on method calls. - - Method attributes - - Methods of ExtensionClass instances can have user-defined - attributes, which are stored in their associated instances. - - For example:: - - class C(ExtensionClass.Base): - - def f(self): - "Get a secret" - .... - - c=C() - - c.f.__roles__=['Trusted People'] - - print c.f.__roles__ # outputs ['Trusted People'] - print c.f__roles__ # outputs ['Trusted People'] - - print C.f.__roles__ # fails, unbound method - - A bound method attribute is set by setting an attribute in it's - instance with a name consisting of the concatination of the - method's '__name__' attribute and the attribute name. - Attributes cannot be set on unbound methods. - - Class initialization - - Normal Python class initialization is similar to but subtley - different from instance initialization. An instance '__init__' - function is called on an instance immediately *after* it is - created. An instance '__init__' function can use instance - information, like it's class and can pass the instance to other - functions. On the other hand, the code in class statements is - executed immediately *before* the class is created. This means - that the code in a class statement cannot use class attributes, - like '__bases__', or pass the class to functions. - - Extension classes provide a mechanism for specifying code to be - run *after* a class has been created. If a class or one of it's - base classes defines a '__class_init__' method, then this method - will be called just after a class has been created. The one - argument passed to the method will be the class, *not* an - instance of the class. - - Useful macros defined in ExtensionClass.h - - A number of useful macros are defined in ExtensionClass.h. - These are documented in 'ExtensionClass.h'. - - Pickleability - - Classes created with ExtensionClass, including extension base - classes are automatically pickleable. The usual gymnastics - necessary to pickle 'non-standard' types are not necessray for - types that have been modified to be extension base classes. - - Status - - The current release of the extension class module is "1.1", - http://www.digicool.com/releases/ExtensionClass/ExtensionClass-1.1.tar.gz. - The core implementation has less than four thousand lines of code, - including comments. This release requires Python 1.4 or higher. - - To find out what's changed in this release, see the - "release notes":release.html. - - "Installation instructions":Installation.html, are provided. - - Issues - - There are a number of issues that came up in the course of this work - and that deserve mention. - - - In Python 1.4, the class extension mechanism described in [4] required - that the first superclass in a list of super-classes must be of the - extended class type. This may not be convenient if mix-in - behavior is desired. If a list of base classes starts with a - standard python class, but includes an extension class, then an - error was raised. It would be more useful if, when a list of base - classes contains one or more objects that are not python classes, - the first such object was used to control the extended class - definition. To get around this, the 'ExtensionClass' module exports - a base extension class, 'Base', that can be used as the first base - class in a list of base classes to assure that an extension - subclass is created. - - Python 1.5 allows the class extension even if the first non-class - object in the list of base classes is not the first object in - the list. This issue appears to go away in Python 1.5, however, - the restriction that the first non-class object in a list of - base classes must be the first in the list may reappear in later - versions of Python. - - - Currently, only one base extension class can define any data in - C. The data layout of subclasses-instances is the same as for the - base class that defines data in C, except that the data structure - is extended to hold an instance dictionary. The data structure - begins with a standard python header, and extension methods expect - the C instance data to occur immediately after the object header. If - two or more base classes defined C data, the methods for the - different base classes would expect their data to be in the same - location. A solution might be to allocate base class instances and - store pointers to these instances in the subclass data structure. - The method binding mechanism would have to be a more complicated - to make sure that methods were bound to the correct base data - structure. Alternatively, the signature of C methods could be - expanded to allow pointers to expected class data to be passed - in addition to object pointers. - - - There is currently no support for sub-classing in C, beyond that - provided by method chains. - - - Rules for mixed-type arithmetic are different for python class - instances than they are for extension type instances. Python - classes can define right and left versions of numeric binary - operators, or they can define a coercion operator for converting - binary operator operands to a common type. For extension types, - only the latter, coercion-based, approach is supported. The - coercion-based approach does not work well for many data types for - which coercion rules depend on the operator. Because extension - classes are based on extension types, they are currently limited - to the coercion-based approach. It should be possible to - extend the extension class implementation to allow both types of - mixed-type arithmetic control. - - - I considered making extension classes immutable, meaning that - class attributes could not be set after class creation. I also - considered making extension subclasses cache inherited - attributes. Both of these are related and attractive for some - applications, however, I decided that it would be better to retain - standard class instance semantics and provide these features as - options at a later time. - - - The extension class module defines new method types to bind C and - python methods to extension class instances. It would be useful - for these method objects to provide access to function call - information, such as the number and names of arguments and the - number of defaults, by parsing extension function documentation - strings. - - Applications - - Aside from test and demonstration applications, the extension class - mechanism has been used to provide an extension-based implementation - of the persistence mechanism described in [1]. We have developed - this further to provide features such as automatic deactivation of - objects not used after some period of time and to provide more - efficient persistent-object cache management. - - Acquisition has been heavily used in our recent products. - Synchonized classes have also been used in recent products. - - Summary - - The extension-class mechanism described here provides a way to add - class services to extension types. It allows: - - - Sub-classing extension classes in Python, - - - Construction of extension class instances by calling extension - classes, - - - Extension classes to provide meta-data, such as unbound methods - and their documentation string. - - In addition, the extension class module provides a relatively - concise example of the use of mechanisms that were added to Python - to support MESS [6], and that were described at the fourth Python - Workshop [4]. It is hoped that this will spur research in improved - and specialized models for class implementation in Python. - - References - -.. [1] Fulton, J., "Providing Persistence for World-Wide-Web Applications", - http://www.digicool.com/papers/Persistence.html, - Proceedings of the 5th Python Workshop. - -.. [2] Page, R. and Cropper, S., "Document Template", - http://www.digicool.com/papers/DocumentTemplate.html, - Proceedings of the 5th Python Workshop. - -.. [3] Beaudry, D., "Deriving Built-In Classes in Python", - http://www.python.org/workshops/1994-11/BuiltInClasses/BuiltInClasses_1.html, - Proceedings of the First International Python Workshop. - -.. [4] Van Rossum, G., "Don Beaudry Hack - MESS", - http://www.python.org/workshops/1996-06/notes/thursday.html, - presented in the Developer's Future Enhancements session of the - 4th Python Workshop. - -.. [5] Fulton, J., "Meta-Type Object", - http://www.digicool.com/jim/MetaType.c, - This is a small proposal, the text of which is contained in a - sample implementation source file, - -.. [6] Beaudry, D., and Ascher, D., "The Meta-Extension Set", - http://starship.skyport.net/~da/mess/. |