customized instance dictionaries, anyone?

Bengt Richter bokr at oz.net
Wed Jan 25 04:57:36 EST 2006


On 24 Jan 2006 09:30:00 -0800, wolfgang.lipp at gmail.com wrote:

>some time after posting my `Linkdict recipe`__ to aspn__
>-- basically, a dictionary with run-time delegational
>lookup, but this is not important here -- i thought gee
>that would be fun to make such a customized dictionary
>thingie an instance dictionary, and get some custom
>namespace behavior out of that.
>
>..  __: http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/465748
>..  __: http://aspn.activestate.com/
>
>here is a simplified example: first, the customized
>dictionary class and a test::
>
>
>    class CustomDict( dict ):
>
>        defaultValue = 'THIS ITEM NOT AVAILABLE'
>
>        def __getitem__( self, name ):
>            try:
>                return super( CustomDict, self ).__getitem__( name )
>            except KeyError:
>                return self.defaultValue
>
>        def __contains__( self, name ):
>            return True
>
>        def has_key( self, name ):
>            return True
>
>    print '----------------------------------------'
>    cd = CustomDict( foo = 'bar' )
>    print cd[ 'foo' ]
>    print cd[ 'bar' ]
>    print 'bar' in cd
>    print cd.has_key( 'bar' )
>
>this gives us::
>
>    ----------------------------------------
>    bar
>    THIS ITEM NOT AVAILABLE
>    True
>    True
>
>so it appears to work. note that we may have failed to
>implement all the conceivable ways to test for
>membership (such as searching through ``keys()``) or to
>retrieve a value for a given key. more on that below.
>now for the class to utilize this definition::
>
>    class X( object ):
>
>        def __init__( self ):
>            self.__dict__ = CustomDict( foo = 'bar' )
>
>and the test code for that::
>
>    print '----------------------------------------'
>    x = X()
>    print x.__dict__[ 'foo' ]
>    print x.__dict__[ 'bar' ]
>    print x.foo
>    print x.bar
>
>which yields::
>
>    ----------------------------------------
>    bar
>    THIS ITEM NOT AVAILABLE
>    bar
>
>    Traceback (most recent call last):
>      File "C:\home\projects\__svn__\sundry\#.py", line 39, in ?
>        print x.bar
>    AttributeError: 'X' object has no attribute 'bar'
>
>ok. so the custom dict *basically* works as expected,
>since it does successfully make ``x.foo`` available --
>no surprise here. unfortunately, looking up ``x.bar``,
>which should really return the default value string,
>causes an ``AttributeError`` to be raised.
>
>now of course given the short definition of
>``CustomDict``, perhaps there is an essential lookup
>method that has not been overwritten but that is
>internally used for attribute lookup. however, i
>carefully tested my actual class (from the recipe
>mentioned above) and also compared the methods defined
>there against the standard ``dict()`` interface, and
>nothing of importance appeared to be missing. i also
>tried to bind the dictionary to the instance earlier, in
>``__new__``, to no avail. am i missing something here?
>
Well, if you compare with the following, maybe something will fall into place?

 >>> class CustomDict( dict ):
 ...     defaultValue = 'THIS ITEM NOT AVAILABLE'
 ...     def __getitem__( self, name ):
 ...         try:
 ...             return super( CustomDict, self ).__getitem__( name )
 ...         except KeyError:
 ...             return self.defaultValue
 ...     def __contains__( self, name ):
 ...         return True
 ...     def has_key( self, name ):
 ...         return True
 ...
 >>> class X( object ):
 ...     __dict__ = property(lambda self:self._dict)
 ...     def __getattr__(self, attr): return self.__dict__[attr]
 ...     def __init__( self ):
 ...         self._dict = CustomDict( foo = 'bar' )
 ...
 >>> x = X()
 >>> print x.__dict__['foo']
 bar
 >>> print x.__dict__['bar']
 THIS ITEM NOT AVAILABLE
 >>> print x.foo
 bar
 >>> print x.bar
 THIS ITEM NOT AVAILABLE

Additional data points:
 >>> x.__dict__
 {'foo': 'bar'}
 >>> X.__dict__
 <dictproxy object at 0x02E814C4>
 >>> X.__dict__['__dict__']
 <property object at 0x02EEF70C>

and

 >>> class Y(object):
 ...     def _getdict(self): print '_getdict'; return self._dict
 ...     __dict__=property(_getdict)
 ...     def __init__( self ):
 ...         self._dict = CustomDict( foo = 'bar' )
 ...
 >>> y = Y()
 >>> y.__dict__
 _getdict
 {'foo': 'bar'}
 >>> y._dict
 {'foo': 'bar'}
 >>> y.foo
 Traceback (most recent call last):
   File "<stdin>", line 1, in ?
 AttributeError: 'Y' object has no attribute 'foo'
 >>> def ga(self, attr): print '__getattr__(%s)'%attr; return self.__dict__[attr]
 ...
 >>> Y.__getattr__ = ga
 >>> y.foo
 __getattr__(foo)
 _getdict
 'bar'

Regards,
Bengt Richter



More information about the Python-list mailing list