[Python-ideas] PEP 447: Adding type.__getdescriptor__

Ronald Oussoren ronaldoussoren at mac.com
Fri Dec 1 06:04:00 EST 2017



> On 1 Dec 2017, at 11:32, Nick Coghlan <ncoghlan at gmail.com> wrote:
> 
> On 1 December 2017 at 19:15, Ronald Oussoren <ronaldoussoren at mac.com> wrote:
> 
>> Maybe, but how would this work with super()? Super walks the MRO of type of
>> the instance, but skips the class on the MRO.  This is not equivalent to
>> walking the MRO of the second class on the MRO when you use multiple
>> inheritance,
>> 
>> This also has some other disadvantages. The first is that
>> tp.__getdescriptor__ would replace the default behaviour for the entire MRO
>> and it would be possible to have different behavior for classes on the MRO.
>> The second, minor. one is that __getdescriptor__ would have to reimplement
>> the default logic of walking the MRO, but that logic is fairly trivial.
> 
> I believe those can both be addressed by structuring the override a
> little differently, and putting it at the level of individual
> attribute retrieval on a specific class (rather than on all of its
> subclasses):
> 
>    def _PyType_Lookup(tp, name):
>        mro = tp.mro()
>        assert isinstance(mro, tuple)
> 
>        for base in mro:
>           assert isinstance(base, type)
> 
>           try:
>               getdesc = base.__dict__["__getdescriptor__"]
>           except KeyError:
>               try:
>                   return base.__dict__[name]
>               except KeyError:
>                   pass
>           else:
>               try:
>                   return getdesc(tp, base, name)
>               except AttributeError:
>                   pass
> 
>        return None
> 
> In that version, the __getdescriptor__ signature would be:
> 
>    def __getdescriptor__(dynamic_cls, base_cls, attr):
>
That’s basically what’s in the PEP, except that the PEP says that type will implement __getdescriptor__ to make cooperative subclassing easier.  The current patch inlines type.__getdescriptor__ in the lookup code for efficiency reasons (that is, the runtime cost for not using this feature is basically a pointer test instead of a function call), but would work just as well without inlining.

I’m pretty sure that the first concern isn’t really there, in the end attribute/descriptor resolution ends up in object and type whose implementation must be magic in some way, even without this PEP. 

The second question is more a design question: what’s the better design, having __getdescriptor__ as a class method on classes or as method on metaclasses? Either one would work, but a class method appears to be easier to use and with the introduction of __init_subclass__ there is a precedent for going for a class method.

The  current PEP claims that a method on a metaclass would be better to avoid subtle problems, but ignores the conceptual cost of adding a metaclass. The subtle problem is that a class can have two direct superclasses with a __getdescriptor__ when using multiple inheritance, but that can already be an issue for other methods and that currently includes __getattribute__ for most of not all usecases where __getdescriptor__ would be useful.

Ronald




More information about the Python-ideas mailing list