[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