tags:

views:

796

answers:

2

I want to override the __getattr__ method on a class to do something fancy but I don't want to break the default behavior.

What's the correct way to do this?

+9  A: 

Overriding __getattr__ should be fine -- __getattr__ is only called as a last resort i.e. if there are no attributes in the instance that match the name. For instance, if you access foo.bar, then __getattr__ will only be called if foo has no attribute called bar. If the attribute is one you don't want to handle, throw AttributeError:

class Foo(object):
    def __getattr__(self, name):
        if some_predicate(name):
            # ...
        else:
            # Default behaviour
            raise AttributeError

However, unlike __getattr__, __getattribute__ will be called first (only works for new style classes i.e. those that inherit from object). In this case, you can preserve default behaviour like so:

class Foo(object):
    def __getattribute__(self, name):
        if some_predicate(name):
            # ...
        else:
            # Default behaviour
            return object.__getattribute__(self, name)

See the Python docs for more.

Michael Williamson
Bah, your edit has the same thing I was showing in my answer, +1.
Roger Pate
+1  A: 
class A(object):
  def __init__(self):
    self.a = 42

  def __getattr__(self, attr):
    if attr in ["b", "c"]:
      return 42
    raise AttributeError("%r object has no attribute %r" %
                         (type(self).__name__, attr))
    # exception text copied from Python2.6

>>> a = A()
>>> a.a
42
>>> a.b
42
>>> a.missing
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 8, in __getattr__
AttributeError: 'A' object has no attribute 'missing'
>>> hasattr(a, "b")
True
>>> hasattr(a, "missing")
False
Roger Pate