473,287 Members | 1,663 Online
Bytes | Software Development & Data Engineering Community
Post Job

Home Posts Topics Members FAQ

Join Bytes to post your question to a community of 473,287 software developers and data experts.

customized instance dictionaries, anyone?

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/Coo.../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?

_wolfgang

Jan 24 '06 #1
3 1481
On 24 Jan 2006 09:30:00 -0800, wo***********@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/Coo.../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
Jan 25 '06 #2
thx! indeed, it worked -- took me some time to figure out how to
implement the setting of attributes, too. i finally managed to get that
done using super:

custom dictionary, unchanged::

class CustomDict( dict ):

defaultValue = 'THIS ITEM NOT AVAILABLE'

def __getitem__( self, name ):
#print 'CustomDict.__getitem__( %r )' % ( 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

dictionary user class::

class X( object ):

def __init__( self ):
#print 'X.__init__()'
self._dict = CustomDict( foo = 'bar' )

@property
def __dict__( self ):
#print 'X.__dict__ ( get() )'
return self._dict

def __getattr__( self, name ):
#print 'X.__getattr__( %r )' % ( name, )
return self.__dict__[ name ]

def __setattr__( self, name, value ):
#print 'X.__setattr__( %r, %r )' % ( name, value, )
if name == '_dict':
return super( X, self ).__setattr__( name, value )
self._dict[ name ] = value

the ``~.__setattr__()`` method tests for the special name ``_dict`` and
defers execution to the super of the ``X`` instance, ``object``. other
stuff is handled by the instance itself.
testing that with ::

x = X()
print x.__dict__[ 'foo' ]
print x.__dict__[ 'bar' ]
print x.foo
print x.bar
print x.__dict__
x.oops = 42
print x.__dict__

yields ::

bar
THIS ITEM NOT AVAILABLE
bar
THIS ITEM NOT AVAILABLE
{'foo': 'bar'}
{'foo': 'bar', 'oops': 42}

as expected.

i tried to reason *why* the usage of a property makes this particular
piece of code work, but i seemingly can't find out. anyone around who
has thoughts on that?

_wolfgang

Jan 25 '06 #3
On 25 Jan 2006 09:35:50 -0800, "wo***********@gmail.com" <wo***********@gmail.com> wrote:
thx! indeed, it worked -- took me some time to figure out how to
implement the setting of attributes, too. i finally managed to get that
done using super: Seems good.
<snip>
the ``~.__setattr__()`` method tests for the special name ``_dict`` and
defers execution to the super of the ``X`` instance, ``object``. other
stuff is handled by the instance itself. seems a clean way to do it.
testing that with ::

x = X()
print x.__dict__[ 'foo' ]
print x.__dict__[ 'bar' ]
print x.foo
print x.bar
print x.__dict__
x.oops = 42
print x.__dict__

yields ::

bar
THIS ITEM NOT AVAILABLE
bar
THIS ITEM NOT AVAILABLE
{'foo': 'bar'}
{'foo': 'bar', 'oops': 42}

as expected.

i tried to reason *why* the usage of a property makes this particular
piece of code work, but i seemingly can't find out. anyone around who
has thoughts on that?

I had an inspiration and I think succeeded in doing what you were originally
trying to do (replace the actual instance dict with your custom dict), which
I tried to do but didn't realize at first that the __init__ setting
of x.__dict__ was really setting x.__dict__['__dict__'] not setting the initial
x.__dict__ itself. __dict__ is a peculiar animal, and looking for an instance's
attribute dict doesn't start at the instance. If you look for instance.__dict__,
it is just like looking for any other attribute, and it starts at type(instance).mro()[0]
looking for a descriptor (which a method also is). But the first thing "found" is
a dict proxy for looking up attributes, and when it looks up '__dict__' it returns
a descriptor, which then gets its __get__ method called with the instance whose '__dict__'
is being sought. You have to use the corresponding __set__ method to set the value of '__dict__'
(in this case the CustomDict instance). Otherwise instance.__dict__ will automatically
be set to {} and then used so you have {'__dict__':CustomDict()} instead of CustomDict() itself.

Once this is initialized correctly, then all the machinery works, except we still need to intercept
__getattr__ for some reason. I suspect this is another symptom of some optimization. One of these
days I will have to look in the source ;-) You would think it could give up on the mro method search
and get the __dict__ normally to get the attribute, but some mechanism is not finding the custom
dict, or else maybe it's bypassing the __getitem__ and going directly to the base dict method.

Someday I'll have to look in the source ;-)

customdict as before
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 ): ... def __getattr__(self, attr):
... return self.__dict__[attr]
... #return type(self).__dict__['__dict__'].__get__(self)[attr]
... def __init__( self, *args, **kw ):
... type(self).__dict__['__dict__'].__set__(self, CustomDict(*args, **kw)
... x = X(foo='bar')
print x.__dict__['foo'] bar print x.__dict__['bar'] THIS ITEM NOT AVAILABLE print x.foo bar print x.bar THIS ITEM NOT AVAILABLE x.oops = 42
print x.__dict__ {'foo': 'bar', 'oops': 42}

Looking at a few things of interest:
vars(x) {'foo': 'bar', 'oops': 42} type(vars(x)) <class '__main__.CustomDict'> type(x.__dict__) <class '__main__.CustomDict'> vars(x)['?'] 'THIS ITEM NOT AVAILABLE' type(x) <class '__main__.X'> type(x).__dict__ <dictproxy object at 0x02E81554> type(x).__dict__['__dict__'] <attribute '__dict__' of 'X' objects> type(x).__dict__['__dict__'].__get__ <method-wrapper object at 0x02EF3B6C> type(x).__dict__['__dict__'].__get__(x) {'foo': 'bar', 'oops': 42} type(type(x).__dict__['__dict__'].__get__(x))

<class '__main__.CustomDict'>

The reason the property was needed before was really several reasons.
First was that x.__dict__ wasn't being set properly, so the internal
machinery wasn't finding the custom dict. I changed the name to _dict
and let it be an ordinary attribute, but then used property to fake
what normal stuff would do if x.__dict__ itself was set, not x.__dict__['__dict__']

Wasted a bunch of time trying to get rid of that __getattr__ ;-/

Regards,
Bengt Richter
Jan 26 '06 #4

This thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

3
by: James | last post by:
Does anyone know if it is possible, in C#, to use a customized window frame? For example, programs like Winamp and AdAware do not use the standard box window frame, but a customized design. ...
0
by: Chris | last post by:
To centralize much of the database connectivity and variable declarations, I decided it would make sense to create my own class that inherits from the page class and derive each of my form classes...
210
by: Christoph Zwerschke | last post by:
This is probably a FAQ, but I dare to ask it nevertheless since I haven't found a satisfying answer yet: Why isn't there an "ordered dictionary" class at least in the standard list? Time and again...
7
by: ProvoWallis | last post by:
I'm still learning python so this might be a crazy question but I thought I would ask anyway. Can anyone tell me if it is possible to join two dictionaries together to create a new dictionary using...
4
by: Gre7g Luterman | last post by:
I suppose I was lulled into complacency by how Python makes so many things look like classes, but I'm starting to realize that they're not, are they? I'm writing a C program which handles Python...
0
by: d80013 | last post by:
Hello all, I am trying to create a Dictionary of dictionaries in VBA. All I do is declare two dictionaries, one temporary one, and add the temporary dictionary to the main one recursively. The...
25
by: Licheng Fang | last post by:
I mean, all the class instances that equal to each other should be reduced into only one instance, which means for instances of this class there's no difference between a is b and a==b. Thank...
1
by: Matthew Schibler | last post by:
I'm a newbie to Python, with some experience using perl (where I used nested arrays and hashes extensively). I am building a script in python for a MUD I play, and I want to use the shelve module...
3
by: teephish | last post by:
Hello, I'm currently in the process of creating a small access database and I'm having some problems with creating a customized search. I would like the user to be able to search a record by last...
2
isladogs
by: isladogs | last post by:
The next Access Europe meeting will be on Wednesday 7 Feb 2024 starting at 18:00 UK time (6PM UTC) and finishing at about 19:30 (7.30PM). In this month's session, the creator of the excellent VBE...
0
by: MeoLessi9 | last post by:
I have VirtualBox installed on Windows 11 and now I would like to install Kali on a virtual machine. However, on the official website, I see two options: "Installer images" and "Virtual machines"....
0
by: DolphinDB | last post by:
The formulas of 101 quantitative trading alphas used by WorldQuant were presented in the paper 101 Formulaic Alphas. However, some formulas are complex, leading to challenges in calculation. Take...
0
by: Aftab Ahmad | last post by:
So, I have written a code for a cmd called "Send WhatsApp Message" to open and send WhatsApp messaage. The code is given below. Dim IE As Object Set IE =...
0
by: ryjfgjl | last post by:
ExcelToDatabase: batch import excel into database automatically...
0
isladogs
by: isladogs | last post by:
The next Access Europe meeting will be on Wednesday 6 Mar 2024 starting at 18:00 UK time (6PM UTC) and finishing at about 19:15 (7.15PM). In this month's session, we are pleased to welcome back...
1
isladogs
by: isladogs | last post by:
The next Access Europe meeting will be on Wednesday 6 Mar 2024 starting at 18:00 UK time (6PM UTC) and finishing at about 19:15 (7.15PM). In this month's session, we are pleased to welcome back...
0
by: ArrayDB | last post by:
The error message I've encountered is; ERROR:root:Error generating model response: exception: access violation writing 0x0000000000005140, which seems to be indicative of an access violation...
1
by: PapaRatzi | last post by:
Hello, I am teaching myself MS Access forms design and Visual Basic. I've created a table to capture a list of Top 30 singles and forms to capture new entries. The final step is a form (unbound)...

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.