[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