__getattr__ is a very nice and powerful method that must be handled with care, otherwise you can discover that it has more power than you expected...
| Python |
1 2 3 4 5 6 7 8 9 | class SuperClass:
def supermethod(self):
return 'Output of "SuperClass.supermethod(self)".'
class SubClass(SuperClass):
def __getattr__(self, name):
if name == 'special':
return 'Value of attribute "special".'
else: raise AttributeError, name # <<< DON'T FORGET THIS LINE !!
|
Discussion
If you forget the last line of __getattr__ above, __getattr__ implicitly returns "None" for every attribute name other than "special" and that includes the (otherwise inherited) "supermethod" attribute, so you finish with an unexpected overload of "supermethod"!


Comments
__getattr__ only comes into play after looking in superclasses. When trying to get attribute/method of an object, the object's superclasses are looked up before the __getattr__:
This will print 'super special'.
(But it IS correct that the value returned by __getattr__ is 'None' if no other is given!) willem broekema
Please Fix. William is right... this recepie is incorrect, and should be fixed (or removed). I'd prefer a fix. (If this were a wiki, I'd just MAKE the fix, but there's no mechanism for that in the cookbook. Yet.)
-- Michael Chermside
another problem: loosing callability. There's another problem if you forget the else-branch: your objects loose callability.
The "NoneType" is not callable is because it is trying to look up "__repr__" in order to display it to you, and so it gets back a None from __getattr__ and promptly tries to call it (because it assumes it's a __repr__). You can see this by adding "print 'getting', attr" to your __getattr__()s
I ran into this very problem which is what led me here. Adding the exception line as in the recepie solved my problem; I believe python checks for AttributeErrors and keeps falling back until it can't fall back anymore.
__repr__ is a special case; it should be one of the only (the only?) one that will trigger the strange "NoneType is not callable" error because, if I understand correctly, it's only when you type in an object at the interactive prompt that the follow pattern is run: try: print getattr(object, '__repr__')() except AttributeError: print generic_repr(object) In all other cases it will happily return None to you which would instantly signal to you "oops"
Sign in to comment