http://aspn.activestate.com/ASPN/Coo.../Recipe/286195
This is a new version of super that automatically determines which
method needs to be called based on the existing stack frames. It's much
nicer for writing cooperative classes. It does have more overhead, but
at this stage I'm not so concerned about that - the important thing is
it actually works.
Note that this uses sys._getframe() magic ...
import sys
_builtin_super = super
def super (self, *p, **kw):
"""
Automatically determine the correct super method and call it.
If there is no corresponding super method, there is no effect
(super just
returns None). This assists in creating cooperative base
classes.
This function is designed to be used with the autosuper
metaclass.
Example of usage:
__metaclass__ = autosuper
class A:
def __init__ (self, a, b):
print 'A.__init__'
print a, b
self.super(a, b)
class B (A):
def __init__ (self, a, b):
print 'B.__init__'
self.super(a, b)
B(1, 2)
produces:
B.__init__
A.__init__
1 2
"""
f = sys._getframe().f_back
# Make sure that we're being called from a bound method
instance = f.f_locals[f.f_code.co_varnames[0]]
assert self is instance
# We'll need this to look up the correct method in the base
classes
fname = f.f_code.co_name
# Find the method we're currently running by scanning the MRO
and comparing
# the code objects - when we find a match, that's the class
whose method
# we're currently executing.
s = None
si = None
for c in type(self).__mro__:
try:
m = getattr(c, fname)
except AttributeError:
continue
if m.im_func.func_code is f.f_code:
s = c
break
# We should *never* fail to find the current class
assert s is not None
# Try to get a base class method. If we don't find one, we're
finished.
try:
m = getattr(_builtin_super(s, self), fname)
except AttributeError:
return None
# If the code object for the super class is the same as the
current code
# object, we've actually picked up the current class again -
which would
# lead to infinite recursion. So we're finished.
try:
if m.func_code is f.f_code:
return None
except AttributeError:
func_code = None
if m is None:
return None
return m(*p, **kw)
class autosuper (type):
def __init__(cls, name, bases, dict):
setattr(cls, 'super', super)
if __name__ == '__main__':
__metaclass__ = autosuper
class A:
def __init__ (self):
print 'A.__init__'
self.super()
def test (self):
print 'A.test'
self.super()
class B (A):
def __init__ (self):
print 'B.__init__'
self.super()
def test (self):
print 'B.test'
self.super()
class C (A):
def __init__ (self):
print 'C.__init__'
self.super()
def test (self):
print 'C.test'
self.super()
class D (B, C):
def __init__ (self):
print 'D.__init__'
self.super()
def test (self):
print 'D.test'
self.super()
A().test()
print
B().test()
print
C().test()
print
D().test()
---------- Run ----------
A.__init__
A.test
B.__init__
A.__init__
B.test
A.test
C.__init__
A.__init__
C.test
A.test
D.__init__
B.__init__
C.__init__
A.__init__
D.test
B.test
C.test
A.test
Output completed (0 sec consumed) - Normal Termination
Tim Delaney