How can I use __setitem__ method of dict object?

Bruno Desthuilliers bdesth.quelquechose at free.quelquepart.fr
Tue Feb 6 14:36:10 EST 2007


jeremito a écrit :
> On Feb 6, 10:59 am, "bruno.desthuilli... at gmail.com"
> <bruno.desthuilli... at gmail.com> wrote:
> 
>>On 6 fév, 16:23, "jeremito" <jerem... at gmail.com> wrote:
>>
(snip)
>>>But I can't even get __setitem__ to run.
>>
>>of course, since your __new__ method returns a dict instance, not a xs
>>instance...
>>There are very few cases where you really need to override the __new__
>>method.
> 
> 
> The reason I create my object with __new__ instead of __init__ is
> because when I use __init__ when a value is set it calls __setitem__.
> This is what I want to happen, but not inside of __init__.   Does this
> make sense? 

It would make sens - if you couldn't call dict.__setitem__ directly.

> I'm sure there is a better/more pythonic way to do this,
> but I'm unsure of what it is.  Can someone show me an example of how
> this should work?
> 
> 
(snip)
>>>Is this what the __setitem__ method is for?
>>
>>Yes. But note that you you need to manually call the superclass's
>>overriden method  - unless you
>>really want to replace it with your own, which is obviously not the
>>case here...
>>
>>Note that if someone manually changes the values of xG, xF, or xS, the
>>computed values of xA and/or xT
>>won't reflect this change. Is that what you want ?
>>
> 
> 
> Eventually (when I figure out how to use __setitem__) I will change
> what happens when xG, xF, or xS are changed so that it also changes xA
> and xT.

Which is not the best way to go IMHO. Unless the computation is very 
intensive (which doesn't seem to be the case here) or it's heavily used 
in big loops *and* the perfs are not good enough, it's better to 
recompute on the fly at read time. And if one of the above cases arises, 
then it will be time to use memoization (ie: cache the result of 
computation, invalidating the cache when needed).

> 
>>Finally, and if I may ask, what is your use-case for subclassing
>>dict ? You don't need this to implement a dict-like object,
>>and it might be simpler in your case to write an ordinary class, then
>>add support for the required subset of the dict interface.
> 
> 
> Eventually I am going to add other features to my class (as I have
> mentioned) so I can't simply use a dict object.

I already understood this. My question is : why do you want to 
*subclass* dict. In Python, inheritence is only about implementation, 
it's *not* needed for polymorphism to work. So you don't have to 
subclass dict to have an object behaving (more or less, that's up to 
you) like a dict.

Here's an alternative implementation, so you get the idea. Note that it 
behaves mostly like a dict (well, not totally, but since we don't know 
which subset of the dict interface you need...), but also like a 
'standard' object, so you can use either cs.['xT'] or cs.xT with the 
same result.

class Xs(dict):
     """
     Xs is a container object to hold information about cross sections.
     """
     _computedkeys = 'xA', 'xT'

     def __init__(self, xS=1.0, xF=1.0, xG=1.0, nu=1.0, debug=0):
         self.xS = xS
         self.xF = xF
         self.xG = xG
         self.nu = nu

     # xA and xT as properties (AKA computed attributes)
     def _get_xA(self):
         return self.xG + self.xF
     def _set_xA(self, dummy):
         raise AttributeError(
             "%s.xA is read-only" % self.__class__.__name__
             )
     xA = property(fset=_set_xA, fget=_get_xA)

     def _get_xT(self):
         return self.xA + self.xS
     def _set_xT(self, dummy):
         raise AttributeError(
             "%s.xT is read-only" % self.__class__.__name__
             )
     xT = property(fset=_set_xT, fget=_get_xT)

     # dict interface support, to be extended if needed
     def __setitem__(self, key, value):
         setattr(self, key, value)

     def __getitem__(self, key):
         return getattr(self, key)

     def keys(self):
         return self.__dict__.keys() + list(self._computedkeys)

     def values(self):
         return self.__dict__.values() \
                + [getattr(self, key) for key in self._computedkeys]

     def items(self):
         return zip(self.keys(), self.values())

     def __iter__(self):
         for k in self.keys():
             yield k
         raise StopIteration

     def __contains__(self, key):
         return key in self.keys()

     def __repr__(self):
         return repr(dict(self.items()))






More information about the Python-list mailing list