[Python-3000] Fixing super anyone? (reflux)

Joel Bender jjb5 at cornell.edu
Thu Apr 26 20:55:14 CEST 2007


I've come late to this thread, and misunderstood what was wrong with 
super(), so a thousand pardons please.  But since that's never stopped 
me before...

Guido van Rossum wrote:

> But:
> 
> class E(D): pass
> 
> print E().f()
> 
> This prints DDBCA which surely isn't right.
> 
> Sounds like the classic bug in such attempts.

About about this?

class _super(property):
     def __init__(self):
         property.__init__(self, self.get_super, None, None)
     def get_super(self, klass):
         class wrapper:
             def __getattr__(self, fn):
                 self.fn = fn
                 return self
             def __call__(self, obj, *args, **kwargs):
                 mro = iter(obj.__class__.__mro__)
                 for cls in mro:
                     if cls is klass:
                         break
                 for cls in mro:
                     f = getattr(cls, self.fn)
                     if f:
                         return f(obj, *args, **kwargs)
                 raise AttributeError, self.fn
         return wrapper()

class _superable(type):
     __super__ = _super()

class A(object):
     __metaclass__ = _superable
     def f(self):
         return "A"

class B(A):
     def f(self):
         return "B" + B.__super__.f(self)

class C(A):
     def f(self):
         return "C" + C.__super__.f(self)

class D(B, C):
     def f(self):
         return "D" + D.__super__.f(self)

class E(D):
     pass

assert E().f() == "DBCA"


Tim Delaney wrote:

 > What I haven't worked out yet is if you should be able to do
 > the following:
 >
 >     class A(autosuper):
 >         def f(self):
 >             print 'A:', super
 >
 >     class B(A):
 >         def f(self):
 >             def inner():
 >                 print 'B:', super
 >                 super.f()
 >             inner()

And here's my version:

class A(object):
     __metaclass__ = _superable
     def f(self):
         return "A"

class B(A):
     def f(self):
         def inner():
             return "B" + B.__super__.f(self)
         inner()

assert B().f() == "BA"


Now, back to the original request, I came up with this:


def super(klass, obj=None):
     class wrapper:
         def __init__(self):
             self.klass = klass
             self.obj = obj
         def __getattr__(self, fn):
             self.fn = fn
             return self
         def __call__(self, *args, **kwargs):
             if not self.obj:
                 self.obj = args[0]
                 args = args[1:]
             mro = iter(self.obj.__class__.__mro__)
             for cls in mro:
                 if cls is self.klass:
                     break
             for cls in mro:
                 f = getattr(cls, self.fn)
                 if f:
                     return f(self.obj, *args, **kwargs)
             raise AttributeError, self.fn
     return wrapper()

class A(object):
     def f(self):
         return "A"

class B(A):
     def f(self):
         return "B" + super(B).f(self)

class C(A):
     def f(self):
         return "C" + super(C, self).f()

class D(B, C):
     def f(self):
         return "D" + super(D, self).f()

class E(D):
     pass

assert E().f() == "DBCA"


I prefer the version in C, but B works as well.  Comments?  Is this 
ground that has already been covered?


Joel



More information about the Python-3000 mailing list