By using this site, you agree to our updated Privacy Policy and our Terms of Use. Manage your Cookies Settings.
449,173 Members | 1,079 Online
Bytes IT Community
+ Ask a Question
Need help? Post your question and get tips & solutions from a community of 449,173 IT Pros & Developers. It's quick & easy.

Improved super/autosuper

P: n/a
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

Jul 18 '05 #1
Share this question for a faster answer!
Share on Google+

This discussion thread is closed

Replies have been disabled for this discussion.