Sean Bollin Sean Bollin - 1 month ago 16
Python Question

Why is AttributeError raised twice?

class ValidatingDB(object):
def __init__(self):
self.exists = 5

def __getattribute__(self, name):
print('Called __getattribute__(%s)' % name)
try:
return super(ValidatingDB, self).__getattribute__(name)
except AttributeError:
value = 'Value for %s' % name
setattr(self, name, value)
return value

data = ValidatingDB()
data.exists
data.foo
data.foo


I would expect that the first call to data.foo would "set" and the second call to data.foo would no longer produce the AttributeError. Why does it raise the AttributeError for each call of data.foo?

Answer

Your code doesn't allow you to see the difference between an AttributeError and an attribute existing. In both cases you get exactly the same result.

So the first data.foo access raises an AttributeError, so a new value is created, set and returned.

The second data.foo access returns that value you already set. This is indistinguishable from the previous expression because in both cases you get a value back.

You'd have to change your code do something else when an AttributeError has been raised. You could add an extra print statement, for example:

def __getattribute__(self, name):
    print('Called __getattribute__(%s)' % name)
    try:
        return super(ValidatingDB, self).__getattribute__(name)
    except AttributeError:
        print('No such attribute, generating a new value')
        value = 'Value for %s' % name
        setattr(self, name, value)
        return value

Now you'll see a difference:

>>> data = ValidatingDB()
>>> data.exists
Called __getattribute__(exists)
5
>>> data.foo
Called __getattribute__(foo)
No such attribute, generating a new value
'Value for foo'
>>> data.foo
Called __getattribute__(foo)
'Value for foo'
Comments