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

Nick Coghlan ncoghlan at gmail.com
Fri Dec 1 06:29:10 EST 2017

On 1 December 2017 at 21:04, Ronald Oussoren <ronaldoussoren at mac.com> wrote:
> 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.

I think it's having it being a method on the metaclass that creates
the infinite regress Mark was worried about: since type's metaclass
*is* type, if "__getdescriptor__" is looked up as a regular descriptor
in its own right, then there's no base case to terminate the recursive

By contrast, defining it as a class method opens up two options:

1. Truly define it as a class method, and expect implementors to call
super().__getdescriptor__() if their own lookup fails. I think this
will be problematic and a good way to get the kinds of subtle problems
that prompted you to initially opt for the metaclass method.

2. Define it as a class method, but have the convention be for the
*caller* to worry about walking the MRO, and hence advise class
implementors to *never* call super() from __getdescriptor__
implementations (since doing so would nest MRO walks, and hence
inevitably have weird outcomes). Emphasise this convention by passing
the current base class from the MRO as the second argument to the

The reason I'm liking option 2 is that it leaves the existing
__getattribute__ implementations fully in charge of the MRO walk, and
*only* offers a way to override the "base.__dict__[name]"  part with a
call to "base.__dict__['__getdescriptor__'](cls, base, name)" instead.


Nick Coghlan   |   ncoghlan at gmail.com   |   Brisbane, Australia

More information about the Python-ideas mailing list