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

1.2k views Asked by At

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.

2

There are 2 answers

0
ekhumoro On BEST ANSWER

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
0
user2357112 On
print abcd.__getattribute__('hello')

abcd.__getattribute__ is not the __getattribute__ method. When you try to evaluate abcd.__getattribute__, you're actually calling

type(abcd).__getattribute__(abcd, '__getattribute__')

which returns None, which you then try to call as if it were a method.