Insensitive Dictionaries (Was: Language change and code breaks)
Joal Heagney
s713221 at student.gu.edu.au
Sun Jul 22 23:59:18 EDT 2001
Peter Mayne wrote:
> Or should dictionaries be changed so that key lookups
> become case-insensitive? That would mean a program that looks for different
> cases of variables and produces example output of {'STRING': 3, 'String': 2,
> 'string': 3} (posted elsewhere in this thread) couldn't be written. 8-)
> Maybe we should change only some dictionaries. I know I'm not going to
> figure out the "right" way of fixing this.
>
> We could (for instance) assume that all variable names are stored in lower
> case, but then A.__dict__['F1']() wouldn't work. How do you explain that
> defining a name in upper case, then doing introspection using the same case,
> doesn't work, just after you've explained that the language is
> case-insensitive? For that matter, how do you explain to beginners that
> Python might be case-insensitive, but 'Python'!='python'?
Well if all we want is some dictionaries to be insensitive (The
cold-hearted bastards *grins*), would this do to begin with? Of course
it needs some expansion so that tuples are expanded insensitively as
well. (Left as an exercise for the reader.*grins*)
>>> from UserDict import UserDict
>>> class InsensitiveDict(UserDict):
def __getitem__(self,key):
if type(key) == type(""):
return self.data[key.lower()]
else:
return self.__dict[key]
def __setitem__(self,key,value):
if type(key) == type(""):
self.data[key.lower()] = value
else:
self.data[key] = value
>>> a = InsensitiveDict()
>>> a['a'] = 1
>>> a['A']
1
>>> a['a']
1
>>> a['A'] = 2
>>> a['a']
2
Only hassle is that it isn't internally case-preserving, especially with
item, key and __repr__ methods.
>>> a = InsensitiveDict()
>>> a['A'] = 1
>>> a.keys()
['a']
>>> a.items()
[('a', 1)]
>>> a
{'a': 1}
Number two is an alternative that internally keeps the first key that is
entered, no matter if it's value is redefined by a different cased key.
>>> class InsensitiveDict2(UserDict):
def __getitem__(self,key):
if self.data.has_key(key):
return self.data[key]
else:
if type(key) == type(""):
for i in self.data.keys():
if i.lower() == key.lower():
return self.data[i]
raise KeyError, key
def __setitem__(self,key,value):
if self.data.has_key(key):
self.data[key] = value
else:
if type(key) == type(""):
nothaskey = 1
for i in self.data.keys():
if i.lower() == key.lower():
self.data[i] = value
haskey = 0
if nothaskey:
self.data[key] = value
else:
self.data[key] = value
>>> b = InsensitiveDict2()
>>> b['A'] = 2
>>> b
{'A': 2}
>>> b['a'] = 3
>>> b
{'A': 3}
Version three keeps the latest case-version key that has been assigned
to in the dictionary. It's the one I prefer most.
>>> class InsensitiveDict3(UserDict):
def __getitem__(self,key):
try:
return self.data[key]
except IndexError:
if type(key) == type(""):
for i in self.data.keys():
if i.lower() == key.lower():
return self.data[i]
else:
raise IndexError
def __setitem__(self,key,value):
if self.data.has_key(key):
self.data[key] = value
else:
if type(key) == type(""):
for i in self.data.keys():
if i.lower() == key.lower():
del self.data[i]
self.data[key] = value
else:
self.data[key] =value
>>> b = InsensitiveDict2()
>>> b['A'] = 2
>>> b
{'A': 2}
>>> b['a'] = 3
>>> b
{'a': 3}
All of these need extra logic that can expand tuples to be truely case
insensitive.
Also, I'm not so sure I like the internal loop over all items in
self.data.keys for the second and third version. Imagine the performance
hits for large dictionaries. Unless there was a need for
case-preservation, in terms of preferences, version one would win out in
this case. Does anyone else have a cleaner method? Perhaps two internal
dictionaries, one case-preserving and one case-insensitive?
--
Joal Heagney is: _____ _____
/\ _ __ __ _ | | _ ___ |
/__\|\ || ||__ |\ || |___|/_\|___] |
/ \ \_||__ ||___| \_|! | | \ \ !
More information about the Python-list
mailing list