Improved super/autosuper

Collapse
This topic is closed.
X
X
 
  • Time
  • Show
Clear All
new posts
  • Delaney, Timothy C (Timothy)

    Improved super/autosuper



    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_var names[0]]
    assert self is instance

    # We'll need this to look up the correct method in the base
    classes
    fname = f.f_code.co_nam e

    # 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).__mr o__:
    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(_builti n_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

Working...