<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 25 Jul 2015, at 17:39, Mark Shannon <<a href="mailto:mark@hotpy.org" class="">mark@hotpy.org</a>> wrote:</div><br class="Apple-interchange-newline"><div 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 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 "__getdescriptor__"<br class="">from type. This special casing should be mentioned in the PEP.<br class=""></div></blockquote><div><br class=""></div>Sure. An alternative is to slightly change the the PEP: use __getdescriptor__ when</div><div>present and directly peek into __dict__ when it is not, and then remove the default</div><div>__getdescriptor__. </div><div><br class=""></div><div>The reason I didn’t do this in the PEP is that I prefer a programming model where</div><div>I can explicitly call the default behaviour. </div><div><br class=""></div><div><blockquote type="cite" class=""><div class=""><br class="">2. The actual implementation in C does not account for the case where the class<br class="">of a metaclass implements __getdescriptor__ and that method returns a value when<br class="">called with "__getdescriptor__" as the argument.<br class=""></div></blockquote><div><br class=""></div>Isn’t that the same problem as with all slots, even when using __getattribute__? That is,</div><div>a meta class that implements __getattribute__ to return implementations for (say)</div><div>__getitem__ won’t work because the interpreter won’t call __getattribute__ to get that</div><div>implementation unless it already knows that the attribute is present. Class creation,</div><div>and __setattr__ on type will not only fill __dict__, but also set slots in the type structure</div><div>as appropriate. The interpreter than uses those slots to determine if a special method</div><div>is present.</div><div><br class=""></div><div>In code:</div><div><br class=""></div><div><div style="margin: 0px; font-size: 11px; font-family: Menlo; color: rgb(52, 187, 199);" class=""><span style="font-variant-ligatures: no-common-ligatures; color: #ce7924" class="">class</span><span style="font-variant-ligatures: no-common-ligatures; color: #000000" class=""> </span>Meta1<span style="font-variant-ligatures: no-common-ligatures; color: #000000" class=""> (</span>type<span style="font-variant-ligatures: no-common-ligatures; color: #000000" class="">):</span></div><div style="margin: 0px; font-size: 11px; font-family: Menlo;" class=""> <span style="font-variant-ligatures: no-common-ligatures; color: #ce7924" class="">def</span> <span style="font-variant-ligatures: no-common-ligatures; color: #34bbc7" class="">__getitem__</span>(self, key):</div><div style="margin: 0px; font-size: 11px; font-family: Menlo;" class=""> <span style="font-variant-ligatures: no-common-ligatures; color: #ce7924" class="">return</span> <span style="font-variant-ligatures: no-common-ligatures; color: #c33720" class="">"<{} {}>"</span>.<span style="font-variant-ligatures: no-common-ligatures; color: #34bbc7" class="">format</span>(self.__name__, key)</div><div style="margin: 0px; font-size: 11px; font-family: Menlo; min-height: 13px;" class=""><br class=""></div><div style="margin: 0px; font-size: 11px; font-family: Menlo;" class=""><span style="font-variant-ligatures: no-common-ligatures; color: #ce7924" class="">class</span> <span style="font-variant-ligatures: no-common-ligatures; color: #34bbc7" class="">Class1</span> (metaclass=Meta1):</div><div style="margin: 0px; font-size: 11px; font-family: Menlo;" class=""> <span style="font-variant-ligatures: no-common-ligatures; color: #ce7924" class="">pass</span></div><div style="margin: 0px; font-size: 11px; font-family: Menlo; min-height: 13px;" class=""><br class=""></div><div style="margin: 0px; font-size: 11px; font-family: Menlo; min-height: 13px;" class=""><br class=""></div><div style="margin: 0px; font-size: 11px; font-family: Menlo; min-height: 13px;" class=""><br class=""></div><div style="margin: 0px; font-size: 11px; font-family: Menlo; color: rgb(52, 187, 199);" class=""><span style="font-variant-ligatures: no-common-ligatures; color: #ce7924" class="">class</span><span style="font-variant-ligatures: no-common-ligatures; color: #000000" class=""> </span>Meta2<span style="font-variant-ligatures: no-common-ligatures; color: #000000" class=""> (</span>type<span style="font-variant-ligatures: no-common-ligatures; color: #000000" class="">):</span></div><div style="margin: 0px; font-size: 11px; font-family: Menlo;" class=""> <span style="font-variant-ligatures: no-common-ligatures; color: #ce7924" class="">def</span> <span style="font-variant-ligatures: no-common-ligatures; color: #34bbc7" class="">__getattribute__</span>(self, name):</div><div style="margin: 0px; font-size: 11px; font-family: Menlo;" class=""> <span style="font-variant-ligatures: no-common-ligatures; color: #ce7924" class="">if</span> name == <span style="font-variant-ligatures: no-common-ligatures; color: #c33720" class="">"__getitem__"</span>:</div><div style="margin: 0px; font-size: 11px; font-family: Menlo;" class=""> <span style="font-variant-ligatures: no-common-ligatures; color: #ce7924" class="">return</span> <span style="font-variant-ligatures: no-common-ligatures; color: #ce7924" class="">lambda</span> key: <span style="font-variant-ligatures: no-common-ligatures; color: #c33720" class="">"<{} {}>"</span>.<span style="font-variant-ligatures: no-common-ligatures; color: #34bbc7" class="">format</span>(self.__name__, key)</div><div style="margin: 0px; font-size: 11px; font-family: Menlo; min-height: 13px;" class=""><br class=""></div><div style="margin: 0px; font-size: 11px; font-family: Menlo;" class=""> <span style="font-variant-ligatures: no-common-ligatures; color: #ce7924" class="">return</span> <span style="font-variant-ligatures: no-common-ligatures; color: #34bbc7" class="">super</span>().__getattribute__(name)</div><div style="margin: 0px; font-size: 11px; font-family: Menlo; min-height: 13px;" class=""><br class=""></div><div style="margin: 0px; font-size: 11px; font-family: Menlo;" class=""><span style="font-variant-ligatures: no-common-ligatures; color: #ce7924" class="">class</span> <span style="font-variant-ligatures: no-common-ligatures; color: #34bbc7" class="">Class2</span> (metaclass=Meta2):</div><div style="margin: 0px; font-size: 11px; font-family: Menlo;" class=""> <span style="font-variant-ligatures: no-common-ligatures; color: #ce7924" class="">pass</span></div><div style="margin: 0px; font-size: 11px; font-family: Menlo; min-height: 13px;" class=""><br class=""></div><div style="margin: 0px; font-size: 11px; font-family: Menlo;" class=""><span style="font-variant-ligatures: no-common-ligatures; color: #34bbc7" class="">print</span>(Class1.__getitem__(<span style="font-variant-ligatures: no-common-ligatures; color: #c33720" class="">"hello"</span>))</div><div style="margin: 0px; font-size: 11px; font-family: Menlo;" class=""><span style="font-variant-ligatures: no-common-ligatures; color: #34bbc7" class="">print</span>(Class1[<span style="font-variant-ligatures: no-common-ligatures; color: #c33720" class="">"hello"</span>])</div><div style="margin: 0px; font-size: 11px; font-family: Menlo; min-height: 13px;" class=""><br class=""></div><div style="margin: 0px; font-size: 11px; font-family: Menlo;" class=""><span style="font-variant-ligatures: no-common-ligatures; color: #34bbc7" class="">print</span>(Class2.__getitem__(<span style="font-variant-ligatures: no-common-ligatures; color: #c33720" class="">"hello"</span>))</div><div style="margin: 0px; font-size: 11px; font-family: Menlo;" class=""><span style="font-variant-ligatures: no-common-ligatures; color: #34bbc7" class="">print</span><span style="font-variant-ligatures: no-common-ligatures; background-color: #00e6e5" class="">(</span>Class2[<span style="font-variant-ligatures: no-common-ligatures; color: #c33720" class="">"hello"</span>]<span style="font-variant-ligatures: no-common-ligatures; background-color: #00e6e5" class="">)</span></div><div class=""><br class=""></div><div class="">The last line causes an exception:</div><div class=""><br class=""></div><div class=""><div style="margin: 0px; font-size: 11px; font-family: Menlo;" class="">Traceback (most recent call last):</div><div style="margin: 0px; font-size: 11px; font-family: Menlo;" class=""> File "demo-getattr.py", line 24, in <module></div><div style="margin: 0px; font-size: 11px; font-family: Menlo;" class=""> print(Class2["hello"])</div><div style="margin: 0px; font-size: 11px; font-family: Menlo;" class="">TypeError: 'Meta2' object is not subscriptable</div></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="">I agree that this should be mentioned in the PEP as it can be confusing.</div><div style="margin: 0px; font-size: 11px; font-family: Menlo;" class=""><br class=""></div><blockquote type="cite" class=""><div class=""><br class=""><br class=""><br class="">Why was "__getattribute_super__" rejected as an alternative? No reason is given.</div></blockquote><blockquote type="cite" class=""><div class=""><br class="">"__getattribute_super__" has none of the problems listed above.<br class=""></div></blockquote><div><br class=""></div><div>Not really. I initially used __getattribute_super__ as the name, but IIRC with</div><div>the same semantics.</div><br class=""><blockquote type="cite" class=""><div class="">Making super(t, obj) delegate to t.__super__(obj) seems consistent with other<br class="">builtin method/classes and doesn't add corner cases to the already complex<br class="">implementation of PyType_Lookup().<br class=""></div></blockquote><div><br class=""></div>A disadvantage of delegation is t.__super__ then reproduce the logic dealing</div><div>with the MRO, while my proposal allows the metaclass to just deal with lookup</div><div>in a specific class object. <br class=""><div><br class=""></div>Implementation complexity is an issue, but it seems to be acceptable so far. The main</div><div>problem w.r.t. additional complexity is that PyType_Lookup can now fail</div><div>with an exception other than an implied AttributeError and that causes</div><div>changes elsewhere in the implementation.</div><div><br class=""></div><div>BTW. The patch for that part is slightly uglier than it needs to be, I currently</div><div>test for PyErr_Occurred() instead of using return codes in a number of places</div><div>to minimise the number of lines changes to make code review easier. That </div><div>needs to be changed before the code would actually be committed.</div><div><br class=""></div><div>Ronald</div><div><br class=""></div><div>P.S. Are you at the EP sprints? I’ll be there until early in the afternoon.</div><div><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>