> On 26 Jul 2015, at 14:18, Mark Shannon <m...@hotpy.org> wrote: > >> On 26 July 2015 at 10:41 Ronald Oussoren <ronaldousso...@mac.com> wrote: >> >> >> >>> On 26 Jul 2015, at 09:14, Ronald Oussoren <ronaldousso...@mac.com> wrote: >>> >>> >>>> On 25 Jul 2015, at 17:39, Mark Shannon <m...@hotpy.org >>>> <mailto:m...@hotpy.org>> wrote: >>>> >>>> Hi, >>>> >>>> On 22/07/15 09:25, Ronald Oussoren wrote:> Hi, >>>>> >>>>> Another summer with another EuroPython, which means its time again to >>>>> try to revive PEP 447… >>>>> >>>> >>>> IMO, there are two main issues with the PEP and implementation. >>>> >>>> 1. The implementation as outlined in the PEP is infinitely recursive, since >>>> the >>>> lookup of "__getdescriptor__" on type must necessarily call >>>> type.__getdescriptor__. >>>> The implementation (in C) special cases classes that inherit >>>> "__getdescriptor__" >>>> from type. This special casing should be mentioned in the PEP. >>> >>> Sure. An alternative is to slightly change the the PEP: use >>> __getdescriptor__ when >>> present and directly peek into __dict__ when it is not, and then remove the >>> default >>> __getdescriptor__. >>> >>> The reason I didn’t do this in the PEP is that I prefer a programming model >>> where >>> I can explicitly call the default behaviour. >> >> I’m not sure there is a problem after all (but am willing to use the >> alternative I describe above), >> although that might be because I’m too much focussed on CPython semantics. >> >> The __getdescriptor__ method is a slot in the type object and because of that >> the >> normal attribute lookup mechanism is side-stepped for methods implemented in >> C. A >> __getdescriptor__ that is implemented on Python is looked up the normal way >> by >> the >> C function that gets added to the type struct for such methods, but that’s >> not >> a problem for >> type itself. >> >> That’s not new for __getdescriptor__ but happens for most other special >> methods as well, >> as I noted in my previous mail, and also happens for the __dict__ lookup >> that’s currently >> used (t.__dict__ is an attribute and should be lookup up using >> __getattribute__, …) > > > "__getdescriptor__" is fundamentally different from "__getattribute__" in that > is defined in terms of itself. > > object.__getattribute__ is defined in terms of type.__getattribute__, but > type.__getattribute__ just does > dictionary lookups.
object.__getattribute__ is actually defined in terms of type.__dict__ and object.__dict__. Type.__getattribute__ is at best used to to find type.__dict__. > However defining type.__getattribute__ in terms of > __descriptor__ causes a circularity as > __descriptor__ has to be looked up on a type. > > So, not only must the cycle be broken by special casing "type", but that > "__getdescriptor__" can be defined > not only by a subclass, but also a metaclass that uses "__getdescriptor__" to > define "__getdescriptor__" on the class. > (and so on for meta-meta classes, etc.) Are the semantics of special methods backed by a member in PyTypeObject part of Python’s semantics, or are those CPython implementation details/warts? In particular that such methods are access directly without using __getattribute__ at all (or at least only indirectly when the method is implemented in Python). That is: >>> class Dict (dict): ... def __getattribute__(self, nm): ... print("Get", nm) ... return dict.__getattribute__(self, nm) ... >>> >>> d = Dict(a=4) >>> d.__getitem__('a') Get __getitem__ 4 >>> d['a'] 4 >>> (And likewise for other special methods, which amongst others means that neither __getattribute__ nor __getdescriptor__ can be used to dynamicly add such methods to a class) In my proposed patch I do special case “type”, but that’s only intended as a (for now unbenchmarked) speed hack. The code would work just as well without the hack because the metatype’s __getdescriptor__ is looked up directly in the PyTypeObject on the C level, without using __getattribute__ and hence without having to use recursion. BTW. I wouldn’t mind dropping the default “type.__getdescriptor__” completely and reword my proposal to state that __getdescriptor__ is used when present, and otherwise __dict__ is accessed directly. That would remove the infinite recursion, as all metaclass chains should at some end up at “type” which then wouldn’t have a “__getdescriptor__”. The reason I added “type.__getdescriptor__” is that IMHO gives a nicer programming model where you can call the superclass implementation in the implementation of __getdescriptor__ in a subclass. Given the minimal semantics of “type.__getdescriptor__” loosing that wouldn’t be too bad to get a better object model. Ronald > > Cheers, > Mark > _______________________________________________ > Python-Dev mailing list > Python-Dev@python.org > https://mail.python.org/mailman/listinfo/python-dev > Unsubscribe: > https://mail.python.org/mailman/options/python-dev/ronaldoussoren%40mac.com
_______________________________________________ Python-Dev mailing list Python-Dev@python.org https://mail.python.org/mailman/listinfo/python-dev Unsubscribe: https://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com