[Python-3000] Fixing super anyone?

Steven Bethard steven.bethard at gmail.com
Wed Apr 25 07:26:37 CEST 2007


On 4/24/07, Steven Bethard <steven.bethard at gmail.com> wrote:
> On 4/24/07, Calvin Spealman <ironfroggy at gmail.com> wrote:
> > I must have miscopied then because it worked perfectly here. Yes, I
> > meant to have the _superdesc defined inside the metaclass __init__,
> > but thought I could pull it out to make it cleaner. I forgot it
> > actually had to be there! Here is the metaclass that works.
> >
> > class autosuper(type):
> >         def __init__(cls, name, bases, clsdict):
> >                 class _superdesc(object):
> >                         def __get__(self, obj, objcls):
> >                                 return super(cls, obj)
> >                 cls.__super__ = _superdesc()
>
> I still get the same error.

I played around with this for a while. Below is some code that does
work. The trick is to redefine super() so that when you're calling
__get__ to bind a method to an instance, you bind it to the Super()
instance, not the original object instance.

class Super(object):
    def __init__(self, type, obj=None):
        if isinstance(obj, Super):
            obj = obj.__obj__
        self.__type__ = type
        self.__obj__ = obj
    def __get__(self, obj, cls=None):
        if obj is None:
            raise Exception('only supports instances')
        else:
            return Super(self.__type__, obj)
    def __getattr__(self, attr):
        mro = iter(self.__obj__.__class__.__mro__)
        for cls in mro:
            if cls is self.__type__:
                break
        for cls in mro:
            if attr in cls.__dict__:
                x = cls.__dict__[attr]
                if hasattr(x, '__get__'):
                    x = x.__get__(self, cls)
                return x
        raise AttributeError, attr

class autosuper(type):
    def __init__(cls, name, bases, clsdict):
        cls.__super__ = Super(cls)

class A:
    __metaclass__ = autosuper
    def f(self):
        return 'A'

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

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

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

assert D().f() == 'DBCA'

See ma, no bytecode hacks! ;-)

STeVe
-- 
I'm not *in*-sane. Indeed, I am so far *out* of sane that you appear a
tiny blip on the distant coast of sanity.
        --- Bucky Katt, Get Fuzzy


More information about the Python-3000 mailing list