How can I use __setitem__ method of dict object?

jeremito jeremit0 at gmail.com
Tue Feb 6 16:00:08 EST 2007


On Feb 6, 2:36 pm, Bruno Desthuilliers
<bdesth.quelquech... at free.quelquepart.fr> wrote:
> 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()))

Thanks a lot for your help.  I think what you have written is much
better than what I could have come up with on my own.  I guess I just
need more experience.
Thanks,
Jeremy




More information about the Python-list mailing list