
On 1 Dec 2017, at 11:32, Nick Coghlan <ncoghlan@gmail.com> wrote:
On 1 December 2017 at 19:15, Ronald Oussoren <ronaldoussoren@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