[Python-Dev] Classes and Metaclasses in Smalltalk (original) (raw)

M.-A. Lemburg mal@lemburg.com
Wed, 02 May 2001 16:04:29 +0200


Here's an implementation of what I currently use to track down the basemethod (taken from mx.Tools):

import types _basemethod_cache = {}

def basemethod(object,method=None,

           cache=_basemethod_cache,InstanceType=types.InstanceType,
           ClassType=types.ClassType,None=None):

""" Return the unbound method that is defined *after* method in the
    inheritance order of object with the same name as method
    (usually called base method or overridden method).

    object can be an instance, class or bound method. method, if
    given, may be a bound or unbound method. If it is not given,
    object must be bound method.

    Note: Unbound methods must be called with an instance as first
    argument.

    The function uses a cache to speed up processing. Changes done
    to the class structure after the first hit will not be noticed
    by the function.

    XXX Rewrite in C to increase performance.

"""
if method is None:
    method = object
    object = method.im_self
defclass = method.im_class
name = method.__name__
if type(object) is InstanceType:
    objclass = object.__class__
elif type(object) is ClassType:
    objclass = object
else:
    objclass = object.im_class

# Check cache
cacheentry = (defclass, name)
basemethod = cache.get(cacheentry, None)
if basemethod is not None:
    if not issubclass(objclass, basemethod.im_class):
        if __debug__:
            sys.stderr.write(
                'basemethod(%s, %s): cached version (%s) mismatch: '
                '%s !-> %s\n' %
                (object, method, basemethod,
                 objclass, basemethod.im_class))
    else:
        return basemethod

# Find defining class
path = [objclass]
while 1:
    if not path:
        raise AttributeError,method
    c = path[0]
    del path[0]
    if c.__bases__:
        # Prepend bases of the class
        path[0:0] = list(c.__bases__)
    if c is defclass:
        # Found (first occurance of) defining class in inheritance
        # graph
        break
    
# Scan rest of path for the next occurance of a method with the
# same name
while 1:
    if not path:
        raise AttributeError,name
    c = path[0]
    basemethod = getattr(c, name, None)
    if basemethod is not None:
        # Found; store in cache and return
        cache[cacheentry] = basemethod
        return basemethod
    del path[0]
raise AttributeError,'method %s' % name

-- Marc-Andre Lemburg


Company & Consulting: http://www.egenix.com/ Python Software: http://www.lemburg.com/python/