super - is (should) it (be) a reserved word?

Roeland Rengelink r.b.rigilink at cable.a2000.nl
Mon Oct 9 20:32:30 EDT 2000


Grant Edwards wrote:
> 
> In article <mailman.971064623.25775.python-list at python.org>, Michal Wallace wrote:
> 
> >> Alex Martelli wrote:
> >> >
> >> > self.__class__.__bases__[0] satisfies this request, I think.
> >>
> >> Not when there is more than one level of inheritance
> >> involved. The class you want to find the base class
> >> of isn't the class of self, it's the class where the
> >> currently executing method was defined, and there's
> >> currently nothing in Python that keeps track of that.
> 
> Excellent point.  I should have thought of that.
> 
> >Why do you need that? Calling a method of a class
> >climbs the hierarchy for you, all the way up to where
> >the method was first defined or last overridden.
> 
> The example I most often run into is in an __init__ method
> where I want to initialize the features my subclass is adding
> and then pass control and the remaining arguments on up to the
> __init__ method one layer up.  The "super" that I want access
> to is the parent of the class containing the reference to
> "super", not the parent of the class of "self".
> 

I think this is close to what you're looking for, although I strongly
recommend
using standard idiom to solve standard problems. i.e. use:

class A(B):
    def __init__(self):
        B.__init__(self)
 
or any of its variants.



Roeland
--
import types, sys

class SuperCaller:
    '''SuperCaller()

class that allows one to write super.do(self) as a smart version of
self.__class__.bases[0].do(self):

It is smart in the sense that 'do' is searched for among the complete
inherentance hierarchy (depth first). The search is started in the
class that defined the method that invokes super.do(), not in the class
from which self was instantiated. E.g: name-resolution works the same
way as with inheritance. (see tets() for an example).

You can do:

class AClass:
    def do(self):
        print 'Hi',

class BClass(AClass):
    def do(self):
        super.do(self)
        print 'Ho',
    
class CClass(BClass):
    def do(self):
        super.do(self)
        print 'He'
        
and expect CClass().do() to result in
Hi Ho He

needs super = SuperCaller() to be defined in *Class' namespace

Violates "explicit is better than implicit" in the most horrible way!'''

    method_name = None
    calling_code = None
        
    def __getattr__(self, method):
        # What do we want to call, and what wants to do it?
        SuperCaller.method_name = method
        try:
            raise Exception
        except Exception:
            frame = sys.exc_info()[2].tb_frame.f_back
        SuperCaller.calling_code = frame.f_code
        return self.super_caller

    def __repr__(self):
        return '<SuperCaller>'

    def find_calling_class(self, cls):
        '''find out what the class is from which
SuperCaller.calling_code was
           calling super.method()'''
        for val in cls.__dict__.values():
            if (type(val) == types.FunctionType and
                val.func_code == SuperCaller.calling_code):
                return cls
        for super in cls.__bases__:
            cls = self.find_calling_class(super)
            if cls:
                return cls

    def find_method(self, cls):
        '''find self.method among the bases of class cls'''
        for super_cls in cls.__bases__:
            if super_cls.__dict__.has_key(SuperCaller.method_name):
                return super_cls.__dict__[SuperCaller.method_name]
            method = self.find_method(super_cls)
            if method:
                return method
        
    def super_caller(self, *pars, **kw):
        # pars[0] is an instance
        # First find the calling class, then find a method among its
bases
        cls = self.find_calling_class(pars[0].__class__)
        meth = self.find_method(cls)
        if not(meth):
            raise AttributeError, "No method %s in bases of %s" % \
                  (SuperCaller.method_name, pars[0].__class__)
        # In 2.0: return meth(*pars, **kw) 
        return apply(meth, pars, kw)

super = SuperCaller()

def test():
    class A:
        def __init__(self):
            print 'A.__init__ called by', self

    class B(A):
        def __init__(self):
            super.__init__(self)   # A.__init__
            print 'B.__init__ called by', self

    class C(B):
        pass

    class D(C):
        def __init__(self):
            super.__init__(self)  # B.__init__
            print 'D.__init__ called by', self

    class E:
        pass

    class F(E, D):
        def __init__(self):
            super.__init__(self)  # D.__init__
            print 'F.__init__ called by', self
    
    print 'Constructing F'
    F()

if __name__ == '__main__':
    test()



More information about the Python-list mailing list