delegate functions to member

Peter Otten __peter__ at web.de
Tue Aug 10 13:17:47 CEST 2010


Ulrich Eckhardt wrote:

> Peter Otten wrote:
>> Use getattr()
>> 
>>>>> class W(object):
>> ...     def __init__(self, wrapped): self._wrapped = wrapped
>> ...     def __getattr__(self, name):
>> ...             return getattr(self._wrapped, name)
>> ...
> 
> I thought there was something like this, thanks! :)
> 
> When I read this, I thought "OK, now I only have check first if the
> attribute can be looked up in 'self' first", but even that isn't the case.

The getattr() call inside __getattr__() raises an AttributeError if it can't 
find an attribute called name in self._wrapped. This very thing you'd have 
to do if you wanted to signal that an attribute doesn't exist, like in

>>> class A:
...     def __getattr__(self, name):
...             if name == "foo": return 42
...             raise AttributeError
...
>>> a = A()
>>> a.foo
42
>>> a.bar
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 4, in __getattr__
AttributeError

> I tried it and added another function to class W above, which I can call
> just as if it was defined in _wrapped, so obviously (?) the __getattr__
> lookup isn't done there.
> 
> So, short follow-up question: Why does this work?

__getattr__() is a fallback that is only tried when the normal lookup fails.
If you need to intercept every attribute lookup use __getattribute__() 
instead:

>> class A(object):
...     def __getattr__(self, name):
...             print "__getattr__(%r)" % name
...             return 42
...     def __getattribute__(self, name):
...             print "__getattribute__(%r)" % name
...             return super(A, self).__getattribute__(name)
...
>>> a = A()
>>> a.foo = "yadda"
>>> a.foo
__getattribute__('foo')
'yadda'
>>> a.bar
__getattribute__('bar')
__getattr__('bar')
42

Peter



More information about the Python-list mailing list