<html><head><meta http-equiv="Content-Type" content="text/html charset=utf-8"></head><body style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;" class=""><br class=""><div><blockquote type="cite" class=""><div class="">On 26 Jul 2015, at 14:18, Mark Shannon <<a href="mailto:mark@hotpy.org" class="">mark@hotpy.org</a>> wrote:</div><br class="Apple-interchange-newline"><div class=""><blockquote type="cite" class="">On 26 July 2015 at 10:41 Ronald Oussoren <<a href="mailto:ronaldoussoren@mac.com" class="">ronaldoussoren@mac.com</a>> wrote:<br class=""><br class=""><br class=""><br class=""><blockquote type="cite" class="">On 26 Jul 2015, at 09:14, Ronald Oussoren <<a href="mailto:ronaldoussoren@mac.com" class="">ronaldoussoren@mac.com</a>> wrote:<br class=""><br class=""><br class=""><blockquote type="cite" class="">On 25 Jul 2015, at 17:39, Mark Shannon <<a href="mailto:mark@hotpy.org" class="">mark@hotpy.org</a><br class=""><<a href="mailto:mark@hotpy.org" class="">mailto:mark@hotpy.org</a>>> wrote:<br class=""><br class="">Hi,<br class=""><br class="">On 22/07/15 09:25, Ronald Oussoren wrote:> Hi,<br class=""><blockquote type="cite" class=""><br class="">Another summer with another EuroPython, which means its time again to <br class="">try to revive PEP 447…<br class=""><br class=""></blockquote><br class="">IMO, there are two main issues with the PEP and implementation.<br class=""><br class="">1. The implementation as outlined in the PEP is infinitely recursive, since<br class="">the<br class="">lookup of "__getdescriptor__" on type must necessarily call<br class="">type.__getdescriptor__.<br class="">The implementation (in C) special cases classes that inherit<br class="">"__getdescriptor__"<br class="">from type. This special casing should be mentioned in the PEP.<br class=""></blockquote><br class="">Sure. An alternative is to slightly change the the PEP: use<br class="">__getdescriptor__ when<br class="">present and directly peek into __dict__ when it is not, and then remove the<br class="">default<br class="">__getdescriptor__. <br class=""><br class="">The reason I didn’t do this in the PEP is that I prefer a programming model<br class="">where<br class="">I can explicitly call the default behaviour. <br class=""></blockquote><br class="">I’m not sure there is a problem after all (but am willing to use the<br class="">alternative I describe above),<br class="">although that might be because I’m too much focussed on CPython semantics.<br class=""><br class="">The __getdescriptor__ method is a slot in the type object and because of that<br class="">the<br class=""> normal attribute lookup mechanism is side-stepped for methods implemented in<br class="">C. A<br class="">__getdescriptor__ that is implemented on Python is looked up the normal way by<br class="">the <br class="">C function that gets added to the type struct for such methods, but that’s not<br class="">a problem for<br class="">type itself.<br class=""><br class="">That’s not new for __getdescriptor__ but happens for most other special<br class="">methods as well,<br class="">as I noted in my previous mail, and also happens for the __dict__ lookup<br class="">that’s currently<br class="">used (t.__dict__ is an attribute and should be lookup up using<br class="">__getattribute__, …)<br class=""></blockquote><br class=""><br class="">"__getdescriptor__" is fundamentally different from "__getattribute__" in that<br class="">is defined in terms of itself.<br class=""><br class="">object.__getattribute__ is defined in terms of type.__getattribute__, but<br class="">type.__getattribute__ just does <br class="">dictionary lookups.</div></blockquote><div><br class=""></div>object.__getattribute__ is actually defined in terms of type.__dict__ and object.__dict__. Type.__getattribute__ is at best used to to find type.__dict__.<br class=""><div><br class=""></div><blockquote type="cite" class=""><div class=""> However defining type.__getattribute__ in terms of<br class="">__descriptor__ causes a circularity as<br class="">__descriptor__ has to be looked up on a type.<br class=""><br class="">So, not only must the cycle be broken by special casing "type", but that<br class="">"__getdescriptor__" can be defined<br class="">not only by a subclass, but also a metaclass that uses "__getdescriptor__" to<br class="">define "__getdescriptor__" on the class.<br class="">(and so on for meta-meta classes, etc.)<br class=""></div></blockquote><div><br class=""></div><div>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:</div><div><br class=""></div><div><div style="margin: 0px; font-size: 11px; font-family: Menlo;" class="">>>> class Dict (dict):</div><div style="margin: 0px; font-size: 11px; font-family: Menlo;" class="">... def __getattribute__(self, nm):</div><div style="margin: 0px; font-size: 11px; font-family: Menlo;" class="">... print("Get", nm)</div><div style="margin: 0px; font-size: 11px; font-family: Menlo;" class="">... return dict.__getattribute__(self, nm)</div><div style="margin: 0px; font-size: 11px; font-family: Menlo;" class="">... </div><div style="margin: 0px; font-size: 11px; font-family: Menlo;" class="">>>> </div><div style="margin: 0px; font-size: 11px; font-family: Menlo;" class="">>>> d = Dict(a=4)</div><div style="margin: 0px; font-size: 11px; font-family: Menlo;" class="">>>> d.__getitem__('a')</div><div style="margin: 0px; font-size: 11px; font-family: Menlo;" class="">Get __getitem__</div><div style="margin: 0px; font-size: 11px; font-family: Menlo;" class="">4</div><div style="margin: 0px; font-size: 11px; font-family: Menlo;" class="">>>> d['a']</div><div style="margin: 0px; font-size: 11px; font-family: Menlo;" class="">4</div><div style="margin: 0px; font-size: 11px; font-family: Menlo;" class="">>>> </div><div style="margin: 0px; font-size: 11px; font-family: Menlo;" class=""><br class=""></div><div style="margin: 0px; font-size: 11px; font-family: Menlo;" class="">(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)</div><div class=""><br class=""></div><div 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.</div><div class=""><br class=""></div><div class="">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__”. </div><div class=""><br class=""></div><div class="">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.</div><div class=""><br class=""></div><div class="">Ronald</div><div class=""><br class=""></div></div><blockquote type="cite" class=""><div class=""><br class="">Cheers,<br class="">Mark<br class="">_______________________________________________<br class="">Python-Dev mailing list<br class=""><a href="mailto:Python-Dev@python.org" class="">Python-Dev@python.org</a><br class="">https://mail.python.org/mailman/listinfo/python-dev<br class="">Unsubscribe: https://mail.python.org/mailman/options/python-dev/ronaldoussoren%40mac.com<br class=""></div></blockquote></div><br class=""></body></html>