ActiveState Code

Recipe 389916: Example setattr & getattr overloading


An example of overloading __setattr__ and __getattr__ in classes. This example maps attribute names to dicitonary members.

Python
 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

Discussion

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.

Comments

  1. 1. At 11:49 a.m. on 3 oct 2007, Gigi Sayfan said:

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

Sign in to comment