ANN: C-Python 2.3.3 Patch to Enable Python Function Subclassing - X1.0

Lenard Lindstrom len-1@telus.net
Wed, 21 Apr 2004 00:43:03 GMT


A C-Python 2.3.3 Patch to Enable Python Function Subclassing.
Experimental Version 1.0

The source code patch and a recompiled python23.dll for win32
can be found at:

http://www3.telus.net/len_l/Function_Subclassing.html

md5 sums:

05e7af6f007c02d3100ca4e5794bd390 *FS-src-X1-0.tgz
(size 64,102 bytes)

9288762a9d2d714db55dae9adc6d844b *FS-win32-bin-X1-0.zip
(size 500,118 bytes)

Requirements:
------------
For the source code patch the Python 2.3.3 final source code
available at www.python.org and a compatible C compiler.

For the win32 binary the Windows version of Python 2.3.3 .

Introduction
------------
This is an experimental patch which contains modified python
interpreter source code files that permit function subclassing.
The python def statement is also extended to simplify creation
of subclass instances. Eg.:

from types import FunctionType
class FunctionSubType(FunctionType):
    def __call__(self, *args, **kwds):
        print 'Hello'
        return super(FunctionSubType, self).__call__(*args, **kwds)

def (FunctionSubType) fn(x): # optional '(<class>)' gives subclass
    return 2*x

fn(12) # prints 'Hello' then returns 24

The optional class specifier works with any expression that evaluates
to a callable accepting the same five arguments as types.FunctionType.
The parenthesis are mandatory. The above syntax was chosen because
it is easy to implement.

Why Function subclassing?
-----------------------
Function subclassing simplifies special method creation. Normally this
is done using wrapper classes like staticmethod. The following is the
subclass equivalent:

from __future__ import division
from types import FunctionType
class staticfunction(FunctionType):
    def __get__(self, object, type):
        return self

# Using it is simple:
# I know this example would be better done with a class method, but
# it is just a simple example. :-)

class Vector2(object):
    def __init__(self, x, y):
        self.x = x
        self.y = y
    def (staticfunction) Normal2(x, y): # Special constructor
        length = (x**2 + y**2)**0.5
        return Vector2(x/length, y/length)

One can write a static method mixin:

class StaticMixin(object):
    """Make a function a static method"""
    def __get__(self, object, type):
        return self

class PosFunction(FunctionType):
    """Ensure all arguments are positive numbers"""
    def __call__(self, *args):
        for i in args:
            if i < 0:
                raise TypeError, "Requires positive number arguments"
        return super(PosFunction, self).__call__(*args)

class StaticPosIntFunc(StaticMixin, FunctionType): pass

...
class Vector(object):
    ...
    def (StaticPosIntFunc) Normal2(x, y):
        ...

It is a matter of opinion whether or not this approach is more elegant
than using wrapper classes. The best way to decide is to try it yourself.

Enjoy.

Lenard Lindstrom
<len-l@telus.net>