[Python-Dev] Hooking into super() attribute resolution

Steve Dower Steve.Dower at microsoft.com
Tue Jul 9 01:21:52 CEST 2013


> From: Ronald Oussoren [mailto:ronaldoussoren at mac.com]
> Sent: Monday, July 8, 2013 0858
>
> On 8 Jul, 2013, at 17:19, Steve Dower <Steve.Dower at microsoft.com> wrote:
> 
> > The only real advantage is a simpler signature and more easily explained
> use (assuming the person you're explaining it to is familiar with metaclasses,
> so most of the hard explaining has been done).
> 
> The signature is as complex as it is to be able to call descr.__get__ with the
> correct arguments. I ended up with the current signature when I added
> __getattribute_super__ to object and removed the tp_dict peeking code
> from super's tp_getattro.
> 
> A way to get a simpler interface again would be a method that returns an
> attribute *without* performing calls to descr.__get__. That could then be
> used for both __getattribute__ and super.__getattribute__, instead of
> peeking in a class' dictionary. I must admit that I haven't thought about the
> ramifactions of this (both functionally and performance wise).  This might
> end up being easier to explain: both normal attribute resolution and super's
> resolution would end up using the same mechanism, with the differences
> being that super doesn't begin resolution at the start of the mro and ignores
> the instance __dict__.  The disadvantage is introducing a new way to affect
> attribute resolution (do I use "__getattribute__" or this new method?).
> 
> The new interface would be something like:
> 
>     @classmethod
>     def __getlocalname__(cls, object, name):
>         pass
> 
> Or as you mentioned later as a __getlocalname__ method on the metaclass.
> The "object" argument wouldn't be necessary to reproduce current
> functionality, and isn't necessary for my usecase as well, but a hook for
> attribute resolution on an instance that doesn't have access to that instance
> feels wrong.

Except that if it's on a metaclass, the 'instance' it has access to is cls. The descriptor side of things is more interesting, but I see no reason why super can't do that itself, since it knows the actual instance to call __get__ with. (Presumably it already does this with the __dict__ lookup, since that won't call __get__ either.)

Explaining the new method is easiest if the default implementation is (literally):

def __getlocalname__(self, name):
    try:
        return self.__dict__[name]
    except KeyError:
        raise AttributeError(name)

which does not do any descriptor resolution (and is only a small step from simply replacing __dict__ with a custom object, which is basically where we started). The only change I've really suggested is making it an instance method that can be implemented on a metaclass if you want it for class members.

> >
> > I'm still not sure that this isn't simply a bug in super. If the superclass's
> metaclass provides a __getattr__ then it should probably use it and abandon
> it's own MRO traversal.
> 
> I'd have to think about this, but on first glance this would mean a change in
> the semantics that a metaclass' __getattr__ currently has.

Exactly. Probably not a great idea to change that.

> >
> > I still haven't thought the edge cases through, and it seems like there'd be
> some with that change, so that's where __getattribute_super__ comes in -
> super can call it without abandoning its MRO traversal.
> >
> > AFAICT, the difference between that and __getlocalattribute__ is that the
> latter would be implemented on a metaclass while the former takes extra
> parameters. I think this functionality is advanced enough that requiring a
> metaclass isn't unreasonable.
> 
> I'm not necessarily oppossed to a solution that requires using a metaclass, I
> already have metaclasses with custom metaclasses in PyObjC and this
> wouldn't add that much complexity to that :-)

I assumed you were - when I was working on similar sort of code they made life extremely easy. 

> Ronald

Steve




More information about the Python-Dev mailing list