method overriding trick

Jeremy Hylton jeremy at cnri.reston.va.us
Fri Nov 12 21:32:03 CET 1999


I suggested a renaming approach for managing method overriding.

class Base:
    def aMethod(self, arg):
        return arg * 2

class Derived1(Base):
    super_aMethod = Base.aMethod

    def aMethod(self, arg):
        return self.super_aMethod(arg) + 1

David suggested implementing the same idea via a getattr hook that
eliminated the need for explicit naming.

import new
class Mixin:
    def __getattr__(self, k):
	if k[:len('super_')] == 'super_':
	    for b in self.__class__.__bases__:
		m = getattr(b, k[len('super_'):], None)
		if m: 
		    return new.instancemethod(m, self, self.__class__)
	    else:
		raise AttributeError, k
	else:
	    raise AttributeError, k

class Base(Mixin):
    def f(self): 
	print 'Base.f'
    
class Sub(Base):
    def f(self):
	print 'Sub.f'
	self.super_f()

I think this approach might work, but there are some details you've
skated over that would need to be worked out.  The main problem is
dealing with an inheritance hierarchy where there are more levels than
two.

class SubSub(Sub):
    def f(self):
        print "SubSub.f"
        self.super_f()

I you call method f on a SubSub object, you'll dump core.  When the
getattr hook is invoked, it will create a method named super_f for the
object.  Because it is first called in SubSub, the getattr hook will
bind super_f to Sub.f.  But Sub.f also references the name super_f, so
it will call itself.

Actually, you'll hit this problem any time you call f in a class
derived from one that implements a method named f.  Even if SubSub
didn't override f, the search for an f would find the most derived
implementation first. 

I think you can solve the problem with private variables.
self.__super_f will get mangled at compile time and you can do a more
complicated search for attribute names that look like they've been
mangled. 

You would also need to do a proper search of the base classes -- the
transitive closure of the search you've actually implemented.  I think
you would also need to stuff the newly created instancemethod into
__dict__ to avoid looking it up every time.

Jeremy





More information about the Python-list mailing list