<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
  <meta content="text/html; charset=windows-1252"
 http-equiv="Content-Type">
</head>
<body bgcolor="#ffffff" text="#000000">
On 20/03/2010 12:00, Pascal Chambon wrote:
<blockquote cite="mid:4BA4B8DE.8060109@wanadoo.fr" type="cite">
  <meta content="text/html; charset=windows-1252"
 http-equiv="Content-Type">
Michael Foord a écrit :
  <blockquote cite="mid:4BA3DD4F.1080209@voidspace.org.uk" type="cite"><br>
On 19/03/2010 18:58, Pascal Chambon wrote: <br>
    <blockquote type="cite">Hello <br>
      <br>
I've already crossed a bunch of articles detailing python's attribute
lookup semantic (__dict__, descriptors, order of base class
traversing...), but I have never seen, so far, an explanation of WHICH
method did waht, exactly. <br>
      <br>
I assumed that getattr(a, b) was the same as a.__getattribute__(b), and
that this __getattribute__ method (or the hidden routine replacing it
when we don't override it in our class) was in charge of doing the
whole job of traversing the object tree, checking descriptors, binding
methods, calling __getattr__ on failure etc. <br>
      <br>
However, the test case below shows that __getattribute__ does NOT call
__getattr__ on failure. So it seems it's an upper levl machinery, in
getattr(), which is in chrge of that last action. <br>
    </blockquote>
    <br>
Python 3 has the behavior you are asking for. It would be a backwards
incompatible change to do it in Python 2 as __getattribute__ *not*
calling __getattr__ is the documented behaviour. <br>
    <br>
Python 3.2a0 (py3k:78770, Mar 7 2010, 20:32:50) <br>
[GCC 4.2.1 (Apple Inc. build 5646) (dot 1)] on darwin <br>
&gt;&gt;&gt; class x: <br>
... def __getattribute__(s, name): <br>
... print ('__getattribute__', name) <br>
... raise AttributeError <br>
... def __getattr__(s, name): <br>
... print ('__getattr__', name) <br>
... <br>
&gt;&gt;&gt; a = x() <br>
&gt;&gt;&gt; a.b <br>
__getattribute__ b <br>
__getattr__ b <br>
  </blockquote>
I'm confused there, because the script you gave behaves the same in
python 2.6. And according to the doc, it's normal, getattr() reacts to
an AttributeError from __getattribute__, by calling __getattr__ :<br>
  <br>
"""<br>
Python 2.6.5 documentation<br>
  <dl class="method">
    <dt id="object.__getattribute__"><tt class="descclassname">object.</tt><tt
 class="descname">__getattribute__</tt><big>(</big><em>self</em>, <em>name</em><big>)</big></dt>
    <dd>
      <p>Called unconditionally to implement attribute accesses for
instances of the
class. If the class also defines <a moz-do-not-send="true"
 title="object.__getattr__" class="reference internal"
 href="http://docs.python.org/reference/datamodel.html#object.__getattr__"><tt
 class="xref docutils literal"><span class="pre">__getattr__()</span></tt></a>,
the
latter will not be
called unless <a moz-do-not-send="true" title="object.__getattribute__"
 class="reference internal"
 href="http://docs.python.org/reference/datamodel.html#object.__getattribute__"><tt
 class="xref docutils literal"><span class="pre">__getattribute__()</span></tt></a>
either calls it explicitly or raises an <a moz-do-not-send="true"
 title="exceptions.AttributeError" class="reference external"
 href="http://docs.python.org/library/exceptions.html#exceptions.AttributeError"><tt
 class="xref docutils literal"><span class="pre">AttributeError</span></tt></a>.
This
method should return the (computed) attribute value
or raise an <a moz-do-not-send="true" title="exceptions.AttributeError"
 class="reference external"
 href="http://docs.python.org/library/exceptions.html#exceptions.AttributeError"><tt
 class="xref docutils literal"><span class="pre">AttributeError</span></tt></a>
exception. In order to avoid infinite
recursion in this method, its implementation should always call the
base class
method with the same name to access any attributes it needs, for
example, <tt class="docutils literal"><span class="pre">object.__getattribute__(self,</span>
      <span class="pre">name)</span></tt>.</p>
    </dd>
  </dl>
"""<br>
  <br>
But the point which for me is still unclear, is : does the default
implementation of __getattribute__ (the one of "object") call
__getattr__ by himself, or does it rely on its caller for that, by
raising an AttributeError ? For Python2, it's blatantly the latter case
which is favoured, but since it looks like an implementation detail at
the moment, I propose we settle it (and document it) once for all.<br>
</blockquote>
<br>
Ah right, my apologies. So it is still documented behaviour -
__getattr__ is obviously called by the Python runtime and not by
__getattribute__. (It isn't just by getattr as the same behaviour is
shown when doing a normal attribute lookup and not via the getattr
function.)<br>
<br>
<blockquote cite="mid:4BA4B8DE.8060109@wanadoo.fr" type="cite"><br>
  <blockquote cite="mid:4BA3DD4F.1080209@voidspace.org.uk" type="cite"><br>
    <br>
This list is not really an appropriate place to ask questions like this
though, comp.lang.python would be better. <br>
    <br>
All the best, <br>
    <br>
Michael Fooord <br>
  </blockquote>
Sorry if I misposted, I just (wrongly ?) assumed that it was more an
undecided, implementation-specific point (since the doc gave possible
behaviours for __getattribute__, without precising which one was the
default one), and thus targetted the hands-in-core-code audience only. <br>
  <br>
</blockquote>
<br>
Well, the documentation you pointed to specifies that __getattr__ will
be called if __getattribute__ raises an AttributeError, it just doesn't
specify that it is done by object.__getattribute__ (which it isn't).<br>
<br>
Michael Foord<br>
<br>
<blockquote cite="mid:4BA4B8DE.8060109@wanadoo.fr" type="cite">Regards,
  <br>
Pascal<br>
  <br>
  <br>
</blockquote>
<br>
<br>
<pre class="moz-signature" cols="72">-- 
<a class="moz-txt-link-freetext" href="http://www.ironpythoninaction.com/">http://www.ironpythoninaction.com/</a>
<a class="moz-txt-link-freetext" href="http://www.voidspace.org.uk/blog">http://www.voidspace.org.uk/blog</a>

READ CAREFULLY. By accepting and reading this email you agree, on behalf of your employer, to release me from all obligations and waivers arising from any and all NON-NEGOTIATED agreements, licenses, terms-of-service, shrinkwrap, clickwrap, browsewrap, confidentiality, non-disclosure, non-compete and acceptable use policies (”BOGUS AGREEMENTS”) that I have entered into with your employer, its partners, licensors, agents and assigns, in perpetuity, without prejudice to my ongoing rights and privileges. You further represent that you have the authority to release me from any BOGUS AGREEMENTS on behalf of your employer.

</pre>
</body>
</html>