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