no-clobber dicts?

3 views
Skip to first unread message

kj

unread,
Aug 3, 2009, 5:07:32 PM8/3/09
to

I use the term "no-clobber dict" to refer to a dictionary D with
the especial property that if K is in D, then

D[K] = V

will raise an exception unless V == D[K]. In other words, D[K]
can be set if K doesn't exist already among D's keys, or if the
assigned value is equal to the current value of D[K]. All other
assignments to D[K] trigger an exception.

The idea here is to detect inconsistencies in the data.

This is a data structure I often need. Before I re-invent the
wheel, I thought I'd ask: is it already available?

TIA!

kynn

r

unread,
Aug 3, 2009, 5:47:54 PM8/3/09
to

Not sure if something like this already exists, but it would be
trivial to implement by overriding dict.__setitem__()

badda-bing baby!

Chris Rebert

unread,
Aug 3, 2009, 6:00:14 PM8/3/09
to r, pytho...@python.org

That is, if you don't care about .update() not preserving the
invariant. Otherwise, one will need to look at the UserDict module.

Cheers,
Chris
--
http://blog.rebertia.com

r

unread,
Aug 3, 2009, 7:39:25 PM8/3/09
to
On Aug 3, 5:00 pm, Chris Rebert <c...@rebertia.com> wrote:
> On Mon, Aug 3, 2009 at 2:47 PM, r<rt8...@gmail.com> wrote:
[snip]

> > Not sure if something like this already exists, but it would be
> > trivial to implement by overriding dict.__setitem__()
>
> That is, if you don't care about .update() not preserving the
> invariant. Otherwise, one will need to look at the UserDict module.
>
> Cheers,
> Chris
> --http://blog.rebertia.com

Good catch Chris. However since the OP said this was for testing
purposes, i just *assumed* he would be smart enough *not* to call
update() on the dict at hand ;-). But sometimes i need to be protected
from myself too -- at least thats what my therapist keeps telling
me :-)

Steven D'Aprano

unread,
Aug 3, 2009, 11:23:20 PM8/3/09
to
On Mon, 03 Aug 2009 21:07:32 +0000, kj wrote:

> I use the term "no-clobber dict" to refer to a dictionary D with the
> especial property that if K is in D, then
>
> D[K] = V
>
> will raise an exception unless V == D[K]. In other words, D[K] can be
> set if K doesn't exist already among D's keys, or if the assigned value
> is equal to the current value of D[K]. All other assignments to D[K]
> trigger an exception.


Coincidentally, I just built something very close to what you ask. Here
it is:

class ConstantNamespace(dict):
"""Dictionary with write-once keys."""
def __delitem__(self, key):
raise TypeError("can't unbind constants")
def __setitem__(self, key, value):
if key in self:
raise TypeError("can't rebind constants")
super(ConstantNamespace, self).__setitem__(key, value)
def clear(self):
raise TypeError('cannot unbind constants')
def pop(self, key, *args):
raise TypeError("cannot pop constants")
def popitem(self):
raise TypeError("cannot pop constants")
def update(self, other):
for key in other:
if key in self:
raise TypeError('cannot update constants')
# If we get here, then we're not modifying anything,
# so okay to proceed.
super(ConstantNamespace, self).update(other)
def copy(self):
c = self.__class__(**self)
return c

I also have a series of unit tests for it if you're interested in them.


--
Steven

alex23

unread,
Aug 4, 2009, 1:33:33 AM8/4/09
to
Steven D'Aprano <ste...@REMOVE.THIS.cybersource.com.au> wrote:
> I also have a series of unit tests for it if you're interested in them.

That's several times today that kj has asked a question and you've
responded with ready-to-go code. If this was Stackoverflow, I'd accuse
you of reputation-whoring...

You _can_ just post your cool code without the double act, y'know! :)

kj

unread,
Aug 4, 2009, 3:29:00 PM8/4/09
to


Thanks. As you note this not quite what I'm looking for, but it's
a good template for it.

kynn

kj

unread,
Aug 4, 2009, 3:30:51 PM8/4/09
to

>On Mon, Aug 3, 2009 at 2:47 PM, r<rt8...@gmail.com> wrote:
>> On Aug 3, 4:07=C2=A0pm, kj <no.em...@please.post> wrote:
>>> I use the term "no-clobber dict" to refer to a dictionary D with
>>> the especial property that if K is in D, then
>>>

>>> =C2=A0 D[K] =3D V
>>>
>>> will raise an exception unless V =3D=3D D[K]. =C2=A0In other words, D[K]


>>> can be set if K doesn't exist already among D's keys, or if the

>>> assigned value is equal to the current value of D[K]. =C2=A0All other


>>> assignments to D[K] trigger an exception.
>>>
>>> The idea here is to detect inconsistencies in the data.
>>>

>>> This is a data structure I often need. =C2=A0Before I re-invent the


>>> wheel, I thought I'd ask: is it already available?
>>>
>>> TIA!
>>>
>>> kynn
>>
>> Not sure if something like this already exists, but it would be
>> trivial to implement by overriding dict.__setitem__()

>That is, if you don't care about .update() not preserving the
>invariant.

The implication here is that .update() does not in turn use
.__setitem__(), which I find a bit surprising.

kynn

kj

unread,
Aug 4, 2009, 4:01:12 PM8/4/09
to

>class ConstantNamespace(dict):
<snip>

>I also have a series of unit tests for it if you're interested in them.

Actually, come to think of it, I think I'll take you up on this.
I'd love to see those tests. Unit testing in Python is in area I
need to work on.

TIA!

kynn

Chris Rebert

unread,
Aug 4, 2009, 4:03:08 PM8/4/09
to pytho...@python.org

The builtin types are allowed to take such shortcuts for performance reasons.

Raymond Hettinger

unread,
Aug 4, 2009, 4:14:29 PM8/4/09
to
[kj]

> The implication here is that .update() does not in turn use
> .__setitem__(), which I find a bit surprising.

It's never wise to make assumptions about this sort of thing.
Every method in a class or type is allowed to directly access
or modify its private, internal data. The implementation is
free to choose whether to limit that access to a few accessors
(i.e. getitem, setitem, delitem, len) or to let all of the
methods have direct access to the underlying data structure.
Even if accessors were used, the choice would be arbitrary
(perhaps delitem() gets implemented in terms of pop() or somesuch).

This is a basic for OO programming. Unless the class documentation
promises to use particular hooks, the implementation is free to
change in any way that doesn't violate the published API (this is
one of the benefits of encapsulation and abstract data types).

In general, if a subclass is overriding, rather than extending,
then it should override *every* method that could be affected.


Raymond


Steven D'Aprano

unread,
Aug 4, 2009, 11:07:26 PM8/4/09
to


No problem. Here you go:

http://www.cybersource.com.au/users/steve/python/constants.py

Comments welcome.

--
Steven

kj

unread,
Aug 5, 2009, 3:58:39 PM8/5/09
to
In <00027aa9$0$2969$c3e...@news.astraweb.com> Steven D'Aprano <st...@REMOVE-THIS-cybersource.com.au> writes:

>No problem. Here you go:

>http://www.cybersource.com.au/users/steve/python/constants.py

Extremely helpful. Thanks!

kynn

Reply all
Reply to author
Forward
0 new messages