foo.bar is compiled to call __getattr__ if invoked in a get context; see CodeCompiler#visitAttribute

On Mon, Jun 23, 2008 at 2:44 PM, Leo Soto M. <leo.soto@gmail.com> wrote:
Here is a short history of __findattr__, __getattr__ and
__getattribute__, and why PyObject#object___getattribute__ can't
directly call PyObject#__getattr__. I learned this in the hard way,
but that's what you get when you attempt to modify a core component of
the runtime without understanding all this:

What are __findattr__ and __getattr__?

 - PyObject#__findattr__: Has the semantics of Python's
__getattribute__ (that is, is called before looking on the object
dict), but returns null instead of throwing Py.AttributeError when the
lookup fails.

 - PyObject#__getattr__: Same as __findattr__ but *does* throws
AttributeError and never returns null. Currently it is implemented in
terms of __findattr__, in the obvious way. PyObject subclasses are
expected to override __findattr__.

When are they used?

 - From Java code wanting to access attributes of PyObjects.
 - When you do getattr(foo, bar) on Python code [and I'd bet that when
you do foo.bar too, but I've not looked at the exact locations].

And what about __getattribute__?

 - There are methods *exposed* through the __getattribute__ descriptor
which get called when you do foo.__getattribute__(bar) or
type(foo).__getattribute__(bar)

But who uses that syntax?

 - Typical use is in custom implementations of __getattribute__:

   class Foo(object):
       def __getattribute__(self, attr):
           if attr == "bar":
               return "bar!"
           else:
               Foo.__getattribute__(self, attr)

 - And who knows who other, what's important is that it should work!

So foo.__getattribute__('bar') should always be the same as
getattribute(foo, 'bar') for new-style classes?

 - Yes. That's why every new-style PyObject subclass overriding
__findattr__ should also expose __getattribute__. And both should
follow exactly the same logic.

Cool. So what if we avoid all that repetition by making
object___getattribute__ call __getattr__?

 - Does *not* work. By doing that object.__getattribute__(x, y) would
call x.object___getattribute__(y) and would end calling
x.__findattr__(y) which would invoke the *overriden* __getattr__
logic, not the *original* object's __getattr__ logic. That's quite bad
for derived types with custom __getattribute__ implementation (such as
the "Foo" class shown above), because this means going into an
infinite loop.

Doh.

What *seems* reasonable now is that each overriden __findattr__()
simply call the exposed __getattribute__ and not the other way around.
If the lookup could be delegated to super, then the __getattribute__
method should invoke super.__findattr__().

--
Leo Soto M.
http://blog.leosoto.com

-------------------------------------------------------------------------
Check out the new SourceForge.net Marketplace.
It's the best place to buy or sell services for
just about anything Open Source.
http://sourceforge.net/services/buy/index.php
_______________________________________________
Jython-dev mailing list
Jython-dev@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/jython-dev



--
Jim Baker
jbaker@zyasoft.com