Bypassing __getattribute__ for attribute access

Adam Donahue adam.donahue at gmail.com
Thu Oct 25 21:03:13 CEST 2007


Bruno,

I appreciate your attempt to answer my questions below, although I
think my main point was lost amongst all your commentary and
assumptions.  :^)      I'm not inexperienced, but I take the blame for
the rambling initial post, though, which probably lead to the
confusion.

So let me be more direct:

>From reading it seems that, indeed, __getattribute__ handles calling
attribute.__get__( obj, type(obj ), which does the binding of the
attribute to the object.

That is:

<thingy>.<attribute>

in turn is a call to

<thingy>.__getattribute__( '<attribute>' )    <1>

The default body of __getattribute__ in turn fetches the associated
value (by traversing the class hierarchy if necessary) and examines
its type in order to determine what to return.

Let's assume the ultimate value associated with the attribute (key) is
v.

If type(v) is a function, __getattribute__ returns
v.__get__( <thingy>, type( <thingy> )
If type(v) is, say, an integer, __getattribute__ returns v unmolested.

And so forth.

So:
>>> class X( object ):
...     a = 1
...     class b( object ): pass
...     def c( self ): pass
...
>>> X.a
1
>>> X.b
<class '__main__.b'>
>>> X.c
<unbound method X.c>
>>> x = X()
>>> x.a
1
>>> x.b
<class '__main__.b'>
>>> x.c
<bound method X.c of <__main__.X object at 0x81b2b4c>>

If my interpretation is correct, the X.c's __getattribute__ call knows
the attribute reference is via a class, and thus returns an unbound
method (though it does convert the value to a method).  Likewise,
x.c's __getattribute__ returns the value as a method bound to the x
instance.

How does __getattribute__ knows the calling context.  Its first
argument is the attribute name from what I can tell, not the object
calling it.

Is this correct so far?

Moving on to __get__.  Assume:

class X( object ):
    def foo(self):
        print `self`
x = X()

Then:

x.foo()

Is similar (perhaps the same as) to:

X.foo.__get__( x, X )()

(__getattribute__ performs the transformation automatically when one
references via the . operator.)

And so one can do:

>>> class X( object ):
...     x = 1
...
>>> def set_x( self, x ): self.x = x
...
>>> x = X()
>>> set_x.__get__( x, X )( 5 )
>>> x.x
5

The logical next question then is how does one best add a new method
to this class so that future references to x.set_x() and X.set_x will
properly resolve?  It seems the answer would be to somehow add to
X.__dict__ a new value, with key 'set_x', value the function set_x.
>From there on the . operator I assume would perform the binding to X
or x as needed on-the-fly.

Adam




More information about the Python-list mailing list