__getattr__ vs __getattribute__ (was Re: Is "a is b" &c)
aleax at aleax.it
Mon Mar 17 09:33:07 CET 2003
<posted & mailed>
> In article <Xp1da.94293$zo2.2505671 at news2.tin.it>,
> Alex Martelli <aleax at aleax.it> wrote:
>> def __getattr__(self, name):
>> if name == 'f': return 
>> raise AttributeError, name
>>NOW, after a=X() or a=Y(), you can choose to:
>> assert a.f is not a.f
No need! The code above will work (perhaps a bit more
slowly!) with the substitution you suggest, but it will
work just as well exactly as I had posted it.
To clarify: in a new-style class, you MAY, if you wish,
override the __getattribute__ method. If you do so,
your override is called EVERY time somebody accesses an
attribute on instances of your class -- your override is
ENTIRELY responsible to supply the instances' attributes.
This generally makes your class's operation quite slow,
and almost inevitably you end up delegating within your
__getattribute__ override up to some base class (most
often to class object) after some twiddling/tweaking.
If and when the ordinary object.__getattribute__ runs,
which is for all attribute accesses unless you do any
overriding, then AFTER trying the usual ways (__slots__,
__dict__, class), if an attribute being accessed is
still not found, THEN your __getattr__ override, if any,
executes. In other words, __getattr__ executes for
accesses to attributes that are NOT defined in any of
the usual ways.
Since in this case attribute 'f' is NOT defined in the
usual way, __getattr__ is quite sufficient (and avoids
imposing useless overhead on all accesses to attributes
that ARE defined by normal means -- not that class X
has many... just those it inherits from class object).
In general, __getattribute__ should be overridden only
if you KNOW you WANT to intercept accesses to some
attributes "defined in normal ways" -- and only if you're
OK with substantial slowdown, and only with some kind of
superclass delegation for cases you're not treating in
some direct way. And more often than not, in my as-yet
limited experiences, you can define a custom metaclass
to do the job instead of __getattribute__, most often
faster, and quite possibly in a more simple way, too.
More information about the Python-list