Improved super/autosuper
Delaney, Timothy C (Timothy)
tdelaney at avaya.com
Sun Jul 4 22:34:05 EDT 2004
Slightly improved version - now works with psyco ...
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
try:
f_locals = f.f_locals
except AttributeError:
# f_locals is not available from psyco stackframes
pass
else:
instance = 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
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()
Tim Delaney
More information about the Python-list
mailing list