[Python-Dev] Classes and Metaclasses in Smalltalk
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/