Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
A Python dictionary sub-class that is case-insensitive when searching, but also preserves the keys as inserted.
class CaselessDictionary(dict):
"""A dictionary with case-insensitive keys.
A dictionary that is case-insensitive when searching, but also preserves
the keys as inserted.
"""
def __init__(self, initval={}):
if isinstance(initval, dict):
for key, value in initval.iteritems():
self.__setitem__(key, value)
elif isinstance(initval, list):
for (key, value) in initval:
self.__setitem__(key, value)
def __contains__(self, key):
return dict.__contains__(self, key.lower())
def __getitem__(self, key):
return dict.__getitem__(self, key.lower())['val']
def __setitem__(self, key, value):
return dict.__setitem__(self, key.lower(),
{'key': key, 'val': value})
def has_key(self, key):
"""Returns True if CaselessDictionary contains key, key, else False.
Deprecated from builtin dict type, and obsolete in Python 3 (removed).
Should use `in` operator instead, as demonstrated here
"""
return key in self
def get(self, key, default=None):
try:
v = dict.__getitem__(self, key.lower())
except KeyError:
return default
else:
return v['val']
def items(self):
return [(v['key'], v['val']) for v in dict.itervalues(self)]
def keys(self):
return [v['key'] for v in dict.itervalues(self)]
def values(self):
return [v['val'] for v in dict.itervalues(self)]
def iteritems(self):
for v in dict.itervalues(self):
yield v['key'], v['val']
def iterkeys(self):
for v in dict.itervalues(self):
yield v['key']
def itervalues(self):
for v in dict.itervalues(self):
yield v['val']
@AdotDdot

This comment has been minimized.

Copy link

@AdotDdot AdotDdot commented Aug 16, 2014

Well done, but it doesn't preserve the original case when the value of an already existing key is changed. For example

>>>x = CaselessDictionary({'KEY' : 'value'})
>>>x.keys()
['KEY']
>>>x['key'] = 'another value'
>>>x.keys()
['key']

If you want to fix it, this seems to work:

 def __setitem__(self, key, value):
     if key in self:
         return dict.__setitem__(self, key.lower(), {'key': dict.__getitem__(self, key.lower())['key'], 'val': value})
     return dict.__setitem__(self, key.lower(), {'key': key, 'val': value})

(Sorry for writing this here, but there aren't pull requests on gist)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment