Python LazyDict

written by maze, on Nov 4, 2008 2:42:00 PM.

I'm a great fan of the dot notation, instead of foo['bar'] hash notation. Also because the Django and Jinja templating engines use dot notation for all their object attribute/key lookups.

You can also use assignments and lookups on a dictionary, using the __setattr__ and __getattr__ methods:

class LazyDict(dict):
    def __getattr__(self, attr):
        if attr in self:
            return self[attr]
        else:
            raise AttributeError, "'%s' object has no attribute '%s'" \
                % (self.__class__.__name__, attr)

    def __setattr__(self, attr, value):
        if hasattr(super(LazyDict, self), attr):
            raise AttributeError, "'%s' object already has attribute '%s'" \
                % (self.__class__.__name__, attr)
        self[attr] = value

This allows you to do:

>>> from lazydict import LazyDict
>>> foo = LazyDict()
>>> foo.bar = 42
>>> foo.bar
42
>>> foo.biz = LazyDict()
>>> foo.biz.qux
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "lazydict.py", line 6, in __getattr__
AttributeError: LazyDict instance has no attribute 'qux'
>>> foo.biz.qux = object()
>>> foo.biz.qux
<object object at 0xb7d26468>

Update Nov 12, 1008

Incorporated Floes' suggestions from the comment below, thanks!

Comments

| Comment by Floes — Nov 10, 2008 11:55:00 PM
gravatar
 

The code you have pasted now makes it an immutable dictionary of sorts:

>>> lazy = LazyDict()
>>> lazy.foo = 'bar'
>>> lazy.foo = 'baz'
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "tidbits.py", line 47, in __setattr__
    % (self.__class__.__name__, attr)
AttributeError: 'LazyDict' object already has attribute 'foo'

Changing the line
        if hasattr(self, attr):
to
        if hasattr(super(LazyDict, self), attr):
fixes this as it only checks for proper dictionary attributes, allowing you to override the ones you're making:

>>> lazy = LazyDict()
>>> lazy.foo = 'bar'
>>> lazy.foo = 'baz'
>>> lazy.foo
'baz'

Putting the __getattr__ logic inside a "try, except KeyError" is another small improvement, depending on your likes and dislikes of course :)

 
| Comment by maze — Nov 13, 2008 6:36:24 PM

Thanks for the suggestion Floes, I updated the post.

 
user
 

Leave a Reply

Visitors

Locations of visitors to this page