<div dir="ltr"><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div>Serhiy's definition sounds recursive (defining __getattr__ to define the behavior of __getattr__) but Mark's suggestion makes his intention unclear since the error message is still the same. Also the word "now" is confusing (does it mean "currently, before the PEP" or "once this PEP is accepted"?)<br><br>It would be clearer to first state that Module.__getattribute__ is currently (before the PEP) essentially defined as<br><br></div>class Module(object):<br></div> def __getattribute__(self, name):<br></div> try:<br></div> return object.__getattribute__(self, name)<br></div> except AttributeError:</div><div> if hasattr(self, '__dict__'):<br></div><div> mod_name = self.__dict__.get(name)</div><div> if isinstance(mod_name, str):<br></div> raise AttributeError("module '%s' has no attribute '%s'" % (mod_name, name))<br></div></div> raise AttributeError("module has no attribute '%s'" % name)<br><br></div>The PEP changes the contents of the except clause to:<br></div><div><br></div><div> if hasattr(self, '__dict__'):</div><div> if '__getattr__' in self.__dict__:<br></div> getter = self.__dict__['__getattr__']</div><div> if not callable(getter):<br></div></div> raise TypeError("<span class="gmail-blob-code-inner"><span class="gmail-pl-s"><span class="gmail-pl-pds"></span>module __getattr__ must be callable<span class="gmail-pl-pds">")<br></span></span></span></div><span class="gmail-blob-code-inner"><span class="gmail-pl-s"><span class="gmail-pl-pds"> return getter(name)<br></span></span></span></div><div><span class="gmail-blob-code-inner"><span class="gmail-pl-s"><span class="gmail-pl-pds"> # Unchanged from here on<br></span></span></span></div><span class="gmail-blob-code-inner"><span class="gmail-pl-s"><span class="gmail-pl-pds"></span></span></span><div> mod_name = self.__dict__.get(name)</div><div> if isinstance(mod_name, str):<br></div> raise AttributeError("module '%s' has no attribute '%s'" % (mod_name, name))<br> raise AttributeError("module has no attribute '%s'" % name)</div><div><br></div><span class="gmail-blob-code-inner"><span class="gmail-pl-s"><span class="gmail-pl-pds"></span></span></span><div><span class="gmail-blob-code-inner"><span class="gmail-pl-s"><span class="gmail-pl-pds">(However exception chaining makes the equivalency still not perfect. And we ignore threading. But how far do we need to go when specifying "equivalent code" to what every implementation should implement natively?)<br></span></span></span></div><div><span class="gmail-blob-code-inner"><span class="gmail-pl-s"><span class="gmail-pl-pds"><br></span></span></span></div></div></div></div></div></div></div></div><div class="gmail_extra"><br><div class="gmail_quote">On Sun, Nov 19, 2017 at 12:48 PM, Mark Shannon <span dir="ltr"><<a href="mailto:mark@hotpy.org" target="_blank">mark@hotpy.org</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><span class=""><br>
<br>
On 19/11/17 20:41, Serhiy Storchaka wrote:<br>
<blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
19.11.17 22:24, Mark Shannon пише:<br>
<blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
Just one comment. Could the new behaviour of attribute lookup on a module be spelled out more explicitly please?<br>
<br>
<br>
I'm guessing it is now something like:<br>
<br>
`module.__getattribute__` is now equivalent to:<br>
<br>
def __getattribute__(mod, name):<br>
try:<br>
return object.__getattribute__(mod, name)<br>
except AttributeError:<br>
try:<br>
getter = mod.__dict__["__getattr__"]<br>
except KeyError:<br>
raise AttributeError(f"module has no attribute '{name}'")<br>
return getter(name)<br>
</blockquote>
<br>
I think it is better to describe in the terms of __getattr__.<br>
<br>
def ModuleType.__getattr__(mod, name):<br>
try:<br>
getter = mod.__dict__["__getattr__"]<br>
except KeyError:<br>
raise AttributeError(f"module has no attribute '{name}'")<br>
return getter(name)<br>
<br>
The implementation of ModuleType.__getattribute__ will be not changed (it is inherited from the object type).<br>
</blockquote>
<br></span>
Not quite, ModuleType overrides object.__getattribute__ in order to provide a better error message. So with your suggestion, the change would be to *not* override object.__getattribute__ and provide the above ModuleType.__getattr__<br>
<br>
Cheers,<br>
Mark.<div class="HOEnZb"><div class="h5"><br>
______________________________<wbr>_________________<br>
Python-Dev mailing list<br>
<a href="mailto:Python-Dev@python.org" target="_blank">Python-Dev@python.org</a><br>
<a href="https://mail.python.org/mailman/listinfo/python-dev" rel="noreferrer" target="_blank">https://mail.python.org/mailma<wbr>n/listinfo/python-dev</a><br>
Unsubscribe: <a href="https://mail.python.org/mailman/options/python-dev/guido%40python.org" rel="noreferrer" target="_blank">https://mail.python.org/mailma<wbr>n/options/python-dev/guido%<wbr>40python.org</a><br>
</div></div></blockquote></div><br><br clear="all"><br>-- <br><div class="gmail_signature" data-smartmail="gmail_signature">--Guido van Rossum (<a href="http://python.org/~guido" target="_blank">python.org/~guido</a>)</div>
</div>