An example of overloading __setattr__ and __getattr__ in classes. This example maps attribute names to dicitonary members.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 | class attrExample(dict):
"""Example of overloading __getatr__ and __setattr__
This example creates a dictionary where members can be accessed as attributes
"""
def __init__(self, indict=None, attribute=None):
if indict is None:
indict = {}
# set any attributes here - before initialisation
# these remain as normal attributes
self.attribute = attribute
dict.__init__(self, indict)
self.__initialised = True
# after initialisation, setting attributes is the same as setting an item
def __getattr__(self, item):
"""Maps values to attributes.
Only called if there *isn't* an attribute with this name
"""
try:
return self.__getitem__(item)
except KeyError:
raise AttributeError(item)
def __setattr__(self, item, value):
"""Maps attributes to values.
Only if we are initialised
"""
if not self.__dict__.has_key('_attrExample__initialised'): # this test allows attributes to be set in the __init__ method
return dict.__setattr__(self, item, value)
elif self.__dict__.has_key(item): # any normal attributes are handled normally
dict.__setattr__(self, item, value)
else:
self.__setitem__(item, value)
if __name__ == '__main__':
example = attrExample(attribute='fish')
print example.attribute
example.fish = 'test'
print example['fish']
print example.fish
|
Overloading __setattr__ and __getattr__ in classes can be a useful way of custmizing attribute access. For example transforming attributes or function arguments as they are called and set.
__getattr__ and __setattr__ don't behave symetrically and you have to take slight care in their use. For example overloading __setattr__ can make it difficult to set normal attributes in the __init__ method of an object.
This example is a subclass of dict - but maps attribtues to dictionary members. It allows you to set normal attributes in the __init__ method. After that setting attributes creates a new dictionary memebr (rather than an attribute).
Fetching an attribute first checks for normal attribtues, if the attribute asked for isn't present it checks for dictionary members.
Download
Copy to clipboard
__getattribute__ hook. There is also the __getattribute__() hook, which is called (if defined) for both exisitng and non-exisitng attributes. If __getattribute__() is called and doesn't raise AttributeError then __getattr__() is not called. If __getattribute__() raises AttributeError then __getattr__ gets another change to save the day.
In the __setattr__ method, this line is never True:
Replacing it with the following makes it better:
Please ignore my previous comment!
(The line is checking for attributes added before self.__initialised is set True)