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