Velocity Reviews - Computer Hardware Reviews

Velocity Reviews > Newsgroups > Programming > Python > How can I use __setitem__ method of dict object?

Reply
Thread Tools

How can I use __setitem__ method of dict object?

 
 
jeremito
Guest
Posts: n/a
 
      02-06-2007
Please excuse me if this is obvious to others, but I can't figure it
out. I am subclassing dict, but want to prevent direct changing of
some key/value pairs. For this I thought I should override the
__setitem__ method as such:


class xs(dict):
"""
XS is a container object to hold information about cross sections.
"""

def __new__(cls, xS=1.0, xF=1.0, xG=1.0, nu=1.0, debug=0):
"""
"""
x = {}
x['xS'] = xS
x['xF'] = xF
x['nu'] = nu
x['xG'] = xG
x['xA'] = x['xG'] + x['xF']
x['xT'] = x['xA'] + x['xS']

return x

def __setitem__(self, key, value):
"""
I have overridden this method to prevent setting xT or xA
outside the
class.
"""
print "I am in __setitem__"
if key == 'xT':
raise AttributeError("""Can't change xT. Please change,
xF, xS, or xG""")


But I can't even get __setitem__ to run. Example:
Python 2.5 (r25:51918, Sep 19 2006, 08:49:13)
[GCC 4.0.1 (Apple Computer, Inc. build 5341)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> import xs
>>> cs = xs.xs()
>>> cs

{'xA': 2.0, 'xF': 1.0, 'xG': 1.0, 'xS': 1.0, 'nu': 1.0, 'xT': 3.0}
>>> cs['xT'] = 3.1415
>>> cs

{'xA': 2.0, 'xF': 1.0, 'xG': 1.0, 'xS': 1.0, 'nu': 1.0, 'xT':
3.1415000000000002}


Is this what the __setitem__ method is for? If not, how can I do what
I want to do?
Thanks in advance,
Jeremy

 
Reply With Quote
 
 
 
 
Steve Holden
Guest
Posts: n/a
 
      02-06-2007
jeremito wrote:
> Please excuse me if this is obvious to others, but I can't figure it
> out. I am subclassing dict, but want to prevent direct changing of
> some key/value pairs. For this I thought I should override the
> __setitem__ method as such:
>
>
> class xs(dict):
> """
> XS is a container object to hold information about cross sections.
> """
>
> def __new__(cls, xS=1.0, xF=1.0, xG=1.0, nu=1.0, debug=0):
> """
> """
> x = {}
> x['xS'] = xS
> x['xF'] = xF
> x['nu'] = nu
> x['xG'] = xG
> x['xA'] = x['xG'] + x['xF']
> x['xT'] = x['xA'] + x['xS']
>
> return x
>
> def __setitem__(self, key, value):
> """
> I have overridden this method to prevent setting xT or xA
> outside the
> class.
> """
> print "I am in __setitem__"
> if key == 'xT':
> raise AttributeError("""Can't change xT. Please change,
> xF, xS, or xG""")
>
>
> But I can't even get __setitem__ to run. Example:
> Python 2.5 (r25:51918, Sep 19 2006, 08:49:13)
> [GCC 4.0.1 (Apple Computer, Inc. build 5341)] on darwin
> Type "help", "copyright", "credits" or "license" for more information.
>>>> import xs
>>>> cs = xs.xs()
>>>> cs

> {'xA': 2.0, 'xF': 1.0, 'xG': 1.0, 'xS': 1.0, 'nu': 1.0, 'xT': 3.0}
>>>> cs['xT'] = 3.1415
>>>> cs

> {'xA': 2.0, 'xF': 1.0, 'xG': 1.0, 'xS': 1.0, 'nu': 1.0, 'xT':
> 3.1415000000000002}
>
>
> Is this what the __setitem__ method is for? If not, how can I do what
> I want to do?


>>> class d(dict):

... def __setitem__(self, k, v):
... print "Setting", k
... dict.__setitem__(self, k, v)
...
>>> dd = d()
>>> dd['steve'] = 'holden'

Setting steve
>>> dd['steve']

'holden'
>>>


I believe the problem is that your __new__ method does not return an
object of type xs but a dict, so it does not inherit the __getitem__
method from xs but instead from dict.

regards
Steve
--
Steve Holden +44 150 684 7255 +1 800 494 3119
Holden Web LLC/Ltd http://www.holdenweb.com
Skype: holdenweb http://del.icio.us/steve.holden
Blog of Note: http://holdenweb.blogspot.com
See you at PyCon? http://us.pycon.org/TX2007

 
Reply With Quote
 
 
 
 
bruno.desthuilliers@gmail.com
Guest
Posts: n/a
 
      02-06-2007
On 6 fév, 16:23, "jeremito" <(E-Mail Removed)> wrote:
> Please excuse me if this is obvious to others, but I can't figure it
> out. I am subclassing dict, but want to prevent direct changing of
> some key/value pairs. For this I thought I should override the
> __setitem__ method as such:
>
> class xs(dict):
> """
> XS is a container object to hold information about cross sections.
> """
>
> def __new__(cls, xS=1.0, xF=1.0, xG=1.0, nu=1.0, debug=0):
> """
> """
> x = {}
> x['xS'] = xS
> x['xF'] = xF
> x['nu'] = nu
> x['xG'] = xG
> x['xA'] = x['xG'] + x['xF']
> x['xT'] = x['xA'] + x['xS']
>
> return x


replace this with:
def __init__(self, xS=1.0, xF=1.0, xG=1.0, nu=1.0, debug=0):
dict.__init__(
self,
xS=xS,
xF=xF,
xG=xG,
nu=nu,
xA=xG + xF,
xT=xG + xF + xS
)

> def __setitem__(self, key, value):
> """
> I have overridden this method to prevent setting xT or xA
> outside the
> class.
> """
> print "I am in __setitem__"
> if key == 'xT':
> raise AttributeError(

"Can't change xT. Please change, xF, xS, or xG"
)
dict.__setitem__(self, key, value)

> 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.

> Example:
> Python 2.5 (r25:51918, Sep 19 2006, 08:49:13)
> [GCC 4.0.1 (Apple Computer, Inc. build 5341)] on darwin
> Type "help", "copyright", "credits" or "license" for more information.>>> import xs
> >>> cs = xs.xs()
> >>> cs

>
> {'xA': 2.0, 'xF': 1.0, 'xG': 1.0, 'xS': 1.0, 'nu': 1.0, 'xT': 3.0}>>> cs['xT'] = 3.1415
> >>> cs

>
> {'xA': 2.0, 'xF': 1.0, 'xG': 1.0, 'xS': 1.0, 'nu': 1.0, 'xT':
> 3.1415000000000002}
>
> 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 ?

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.

My 2 cents...

 
Reply With Quote
 
jeremito
Guest
Posts: n/a
 
      02-06-2007
On Feb 6, 10:59 am, "(E-Mail Removed)"
<(E-Mail Removed)> wrote:
> On 6 fév, 16:23, "jeremito" <(E-Mail Removed)> wrote:
>
>
>
> > Please excuse me if this is obvious to others, but I can't figure it
> > out. I am subclassing dict, but want to prevent direct changing of
> > some key/value pairs. For this I thought I should override the
> > __setitem__ method as such:

>
> > class xs(dict):
> > """
> > XS is a container object to hold information about cross sections.
> > """

>
> > def __new__(cls, xS=1.0, xF=1.0, xG=1.0, nu=1.0, debug=0):
> > """
> > """
> > x = {}
> > x['xS'] = xS
> > x['xF'] = xF
> > x['nu'] = nu
> > x['xG'] = xG
> > x['xA'] = x['xG'] + x['xF']
> > x['xT'] = x['xA'] + x['xS']

>
> > return x

>
> replace this with:
> def __init__(self, xS=1.0, xF=1.0, xG=1.0, nu=1.0, debug=0):
> dict.__init__(
> self,
> xS=xS,
> xF=xF,
> xG=xG,
> nu=nu,
> xA=xG + xF,
> xT=xG + xF + xS
> )
>
> > def __setitem__(self, key, value):
> > """
> > I have overridden this method to prevent setting xT or xA
> > outside the
> > class.
> > """
> > print "I am in __setitem__"
> > if key == 'xT':
> > raise AttributeError(

>
> "Can't change xT. Please change, xF, xS, or xG"
> )
> dict.__setitem__(self, key, value)
>
> > 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? 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?


>
> > Example:
> > Python 2.5 (r25:51918, Sep 19 2006, 08:49:13)
> > [GCC 4.0.1 (Apple Computer, Inc. build 5341)] on darwin
> > Type "help", "copyright", "credits" or "license" for more information.>>> import xs
> > >>> cs = xs.xs()
> > >>> cs

>
> > {'xA': 2.0, 'xF': 1.0, 'xG': 1.0, 'xS': 1.0, 'nu': 1.0, 'xT': 3.0}>>> cs['xT'] = 3.1415
> > >>> cs

>
> > {'xA': 2.0, 'xF': 1.0, 'xG': 1.0, 'xS': 1.0, 'nu': 1.0, 'xT':
> > 3.1415000000000002}

>
> > 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.

> 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.

>
> My 2 cents...


Thanks again,
Jeremy

 
Reply With Quote
 
Gabriel Genellina
Guest
Posts: n/a
 
      02-06-2007
"jeremito" <(E-Mail Removed)> escribió en el mensaje
news:(E-Mail Removed) oups.com...

> Please excuse me if this is obvious to others, but I can't figure it
> out. I am subclassing dict, but want to prevent direct changing of
> some key/value pairs. For this I thought I should override the
> __setitem__ method as such:
> if key == 'xT':
> raise AttributeError("""Can't change xT. Please change,
> xF, xS, or xG""")


Why using a dictionary? I'd use a simple class with properties:

py> class Xs(object): # class names should be Uppercase
.... def __init__(self, xS=1.0, xF=1.0, xG=1.0, nu=1.0, debug=0):
.... self.xS = xS
.... self.xF = xF
.... self.nu = nu
.... self.xG = xG
.... xA = property(fget=lambda self: self.xG + self.xF)
.... xT = property(fget=lambda self: self.xA + self.xS)
....
py> xs = Xs(1.0, 0.95, 0.80, 0.70)
py> print xs.xG
0.8
py> print xs.xA
1.75
py> print xs.xT
2.75
py> xs.xG = 0.5
py> print xs.xA
1.45
py> print xs.xT
2.45
py> xs.xA = 1.5
Traceback (most recent call last):
File "<stdin>", line 1, in ?
AttributeError: can't set attribute
py> xs.xT = 1.2
Traceback (most recent call last):
File "<stdin>", line 1, in ?
AttributeError: can't set attribute
py>

--
Gabriel Genellina


 
Reply With Quote
 
Bruno Desthuilliers
Guest
Posts: n/a
 
      02-06-2007
jeremito a écrit :
> On Feb 6, 10:59 am, "(E-Mail Removed)"
> <(E-Mail Removed)> wrote:
>
>>On 6 fév, 16:23, "jeremito" <(E-Mail Removed)> 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()))



 
Reply With Quote
 
jeremito
Guest
Posts: n/a
 
      02-06-2007
On Feb 6, 2:36 pm, Bruno Desthuilliers
<(E-Mail Removed)> wrote:
> jeremito a écrit :
>
>
>
> > On Feb 6, 10:59 am, "(E-Mail Removed)"
> > <(E-Mail Removed)> wrote:

>
> >>On 6 fév, 16:23, "jeremito" <(E-Mail Removed)> 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

 
Reply With Quote
 
Bruno Desthuilliers
Guest
Posts: n/a
 
      02-06-2007
jeremito a écrit :
> On Feb 6, 2:36 pm, Bruno Desthuilliers
> <(E-Mail Removed)> wrote:
>

(snip)

>>Here's an alternative implementation, so you get the idea.
>>
>>class Xs(dict):


oops ! I meant:
class Xs(object):

of course...

(snip)
> I guess I just
> need more experience.


Possibly - but not only. You may want to have a look at the
FineManual(tm) for all this kind of "magic", starting with :
http://docs.python.org/ref/specialnames.html
http://docs.python.org/ref/sequence-types.html

HTH
 
Reply With Quote
 
jeremito
Guest
Posts: n/a
 
      02-07-2007
On Feb 6, 5:10 pm, Bruno Desthuilliers
<(E-Mail Removed)> wrote:
> jeremito a écrit :
> > On Feb 6, 2:36 pm, Bruno Desthuilliers > <(E-Mail Removed)> wrote:

>
> >

> (snip)
>
> >>Here's an alternative implementation, so you get the idea.
> >>
> >>class Xs(dict):

>
> oops ! I meant:
> class Xs(object):
>
> of course...
>
> (snip)
>
> > I guess I just
> > need more experience.

>
> Possibly - but not only. You may want to have a look at the
> FineManual(tm) for all this kind of "magic", starting with :http://docs.python.org/ref/specialna...nce-types.html
>
> HTH


Thanks again! Sometimes the problem is simply not knowing where to
find the documentation, or finding the right portion of the
documentation. Your help has been invaluable.

Jeremy

 
Reply With Quote
 
jeremito
Guest
Posts: n/a
 
      02-07-2007
On Feb 7, 8:28 am, "jeremito" <(E-Mail Removed)> wrote:
> On Feb 6, 5:10 pm, Bruno Desthuilliers
>
>
>
> <(E-Mail Removed)> wrote:
> > jeremito a écrit :
> > > On Feb 6, 2:36 pm, Bruno Desthuilliers > <(E-Mail Removed)> wrote:

>
> > (snip)

>
> > >>Here's an alternative implementation, so you get the idea.

>
> > >>class Xs(dict):

>
> > oops ! I meant:
> > class Xs(object):

>
> > of course...

>
> > (snip)

>
> > > I guess I just
> > > need more experience.

>
> > Possibly - but not only. You may want to have a look at the
> > FineManual(tm) for all this kind of "magic", starting with :http://docs..python.org/ref/specialn....python.org/re...

>
> > HTH

>
> Thanks again! Sometimes the problem is simply not knowing where to
> find the documentation, or finding the right portion of the
> documentation. Your help has been invaluable.
>
> Jeremy


One more question. I will be asking for the value of cs.xT *many*
(~millions) times. Therefore I don't want it's value to be calculated
on the fly. How can I set the value of xT whenever xS, xF, or xG are
changed, but not allow it to be set directly? From the example given
previously, it seems like it can't be done this way.

Thans,
Jeremy

 
Reply With Quote
 
 
 
Reply

Thread Tools

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Trackbacks are On
Pingbacks are On
Refbacks are Off


Similar Threads
Thread Thread Starter Forum Replies Last Post
Re: How include a large array? Edward A. Falk C Programming 1 04-04-2013 08:07 PM
dict.has_key(x) versus 'x in dict' Paul Melis Python 48 12-15-2006 05:55 PM
Inconsistency in dictionary behaviour: dict(dict) not calling __setitem__ Almad Python 8 12-14-2006 07:37 PM
dict!ident as equivalent of dict["ident"] Alexander Kozlovsky Python 5 05-22-2006 08:06 AM
Re: dict->XML->dict? Or, passing small hashes through text? Skip Montanaro Python 0 08-15-2003 03:46 PM



Advertisments