Python has no equivalent to Java's "super" keyword (so that some part of a method can be delegated to the superclass), but it's easy to get similar convenience despite Python's multiple-inheritance generality.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 | class CallbaseError(AttributeError):
pass
def callbase(obj, base, methodname='__init__', args=(), raiseIfMissing=None):
try: method = getattr(base, methodname)
except AttributeError:
if raiseIfMissing:
raise CallbaseError, methodname
return None
if args is None: args = ()
return method(obj, *args)
# an example: ensure __init__ is called w/o args on _all_ bases
# (if present; ignore no-such-method issues)
class A(B, C, D, E):
def __init__(self):
for base in A.__bases__:
callbase(self, base)
# class-A-specific initialization here
self.cachePlokki = {}
# another typical use case: override a method in some base,
# also providing some other stuff around it; e.g. for cache
# on-demand purposes
def getPlokki(self, *args):
try: return self.cachePlokki[args]
except IndexError: pass
for base in self.__class__.__bases__:
try: result=callbase(self, base, 'getPlokki', args, 1)
except CallbaseError: pass
else: break
# ok to raise here if result still not bound
self.cachePlokki[args] = result
return result
|
A frequent need when using inheritance is to delegate part or all of a method's execution to a superclass (even though we override the method, e.g. to provide extra features, the superclass's implementation is still needed as a part of our own). It's OK to do this explicitly to 'the' single superclass in question IF we know which one it is; but, particularly with multiple inheritance, we may not know (we may move methods between superclasses and don't want to depend on that in the subclass we're writing; we may need to call _all_ implementations in various direct superclasses of some method, particularly for special stuff such as __init__ and __del__).
The callbase function provides an example of a reasonably simple use of metaprogramming (introspection, aka reflection) -- it looks for the method by name in a given base-class, and calls it if found, with some typical tweaks (either ignore or raise a special error if not found). It can be called in a loop over __bases__ -- asking it to raise, and breaking the loop as soon as it doesn't raise, if we only want the first-found superclass implementation, or just looping all the way if we want all such implementations.
Like all 'practical' applications of metaprogramming to everyday programming tasks, this needs to be used with caution and good judgment -- it's VERY easy to get overboard with enthusiasm for such possibilities, and forget that simplicity is a key criterion!
Slightly more generalized. By changing:
to:
you get a version of the snippet that can be used in other classes without modification.
super(). Does this need updating for Python 2.2 and its new super() function?