Welcome, guest | Sign In | My Account | Store | Cart

__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, 9 lines
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 !!

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"!

6 comments

willem broekema 23 years ago  # | flag

__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__:

class SuperClass:
    special = 'super special'

class SubClass(SuperClass):
    def __getattr__(self, name):
        if name == 'special':
            return 'sub special'

if __name__ == '__main__':
    S = SubClass()
    print S.special

This will print 'super special'.

(But it IS correct that the value returned by __getattr__ is 'None' if no other is given!) willem broekema

Michael Chermside 22 years, 11 months ago  # | flag

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

Martin Schmettow 21 years, 2 months ago  # | flag

another problem: loosing callability. There's another problem if you forget the else-branch: your objects loose callability.

class Test:
    def __init__(self):
        pass
    def __getattr__(self,name):
        if name == 'myattr':
            return 'value of myattr'

test = Test()
test
Traceback (most recent call last):
  File "", line 1, in ?
TypeError: 'NoneType' object is not callable
dum dee 17 years, 10 months ago  # | flag

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"

dum dee 17 years, 10 months ago  # | flag
And in fact, according to the language reference:
"This method should return the (computed) attribute value or raise an AttributeError exception."
Lance E Sloan 7 years, 8 months ago  # | flag

The example given by Martin Schmettow only fails in the Python interactive interpreter for the reasons given by dum dee. Placing the code in a file and executing it works the same with or without an else clause.

Note that what Mr. Schmettow describes as "callability" is actually just a reference. If the code were to call the instance it created, it would need to use test(), with parentheses.

Created by Jose Sebrosa on Mon, 12 Mar 2001 (PSF)
Python recipes (4591)
Jose Sebrosa's recipes (2)

Required Modules

  • (none specified)

Other Information and Tasks