no-clobber dicts?

K

kj

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

r

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

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

badda-bing baby!
 
C

Chris Rebert

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

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
 
R

r

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 :)
 
S

Steven D'Aprano

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

alex23

Steven D'Aprano said:
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! :)
 
K

kj

In said:
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


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

kynn
 
K

kj

In said:
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
 
K

kj

In said:
class ConstantNamespace(dict):
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
 
C

Chris Rebert

In said:
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.

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

Cheers,
Chris
 
R

Raymond Hettinger

[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
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,766
Messages
2,569,569
Members
45,042
Latest member
icassiem

Latest Threads

Top