Search code examples
pythontypeerrorgetattribute

Why does __getattribute__ fail with: TypeError: 'NoneType' object is not callable


This is my first question here and also my first project in Python.

I'm trying to store instances of a class called Ip500Device:

class Ip500Device(object):

    list = []
    def __init__(self, shortMac, mac, status, deviceType):
        self.__shortMac =shortMac
        self.__mac=mac
        self.__status=status
        self.__deviceType=deviceType
        self.__nbOfObjects=0
        Ip500Device.list.append(self)    

    def __getattribute__(self, att):
        if att=='hello':
            return 0

This first test is just a 'hello', but after that I want to get all the attributes.

From an other class, I'm creating devices object and adding them to a list:

self.__ip500DevicesLst.append(Ip500Device.Ip500Device(lst[0],lst[1],lst[2],lst[3]))
for abcd in self.__ip500DevicesLst:
       print abcd.__getattribute__('hello')

But when I try to print, the program returns this message:

TypeError: 'NoneType' object is not callable

I don't understand really well how to store class instances in Python.


Solution

  • The error happens because __getattribute__ is called for all attributes, and you have defined it to return None for everything other than "hello". Since __getattribute__ is itself an attribute, when you try to call it you will get a TypeError.

    This problem can be fixed by calling the base-class method for unhandled attributes:

    >>> class Ip500Device(object):
    ...     def __getattribute__(self, att):
    ...         print('getattribute: %r' % att)
    ...         if att == 'hello':
    ...             return 0
    ...         return super(Ip500Device, self).__getattribute__(att)
    ...
    >>> abcd = Ip500Device()
    >>> abcd.__getattribute__('hello')
    getattribute: '__getattribute__'
    getattribute: 'hello'
    0
    

    However, it is better to define __getattr__, since that is only called for attributes which don't already exist:

    >>> class Ip500Device(object):
    ...     def __getattr__(self, att):
    ...         print('getattr: %r' % att)
    ...         if att == 'hello':
    ...             return 0
    ...         raise AttributeError(att)
    ...
    >>> abcd = Ip500Device()
    >>> abcd.hello
    getattr: 'hello'
    0
    >>> abcd.foo = 10
    >>> abcd.foo
    10
    

    Finally, note that if all you want to do is access attributes by name, you can use the built-in getattr function:

    >>> class Ip500Device(object): pass
    ...
    >>> abcd = Ip500Device()
    >>> abcd.foo = 10
    >>> getattr(abcd, 'foo')
    10