I have the following datastructure to perform a longest-match lookup via nested dicts. For example. cs['a b c d']
with a
and a b c
being in the structure will return a b c
and the remainder d
.
I wonder if there's a better way to implement the _lookup
method and possible the __setitem__
method. I'm also not completely sure if the way __getitem__
works (returning a tuple with the data in the structure and the remainder of the input) isn't a bit confusing when used with the []
operator.
class CommandStorage(object):
"""Stores multi-part commands.
Performs fast lookups returning the command and any arguments which were
not part of the command.
"""
def __init__(self, commands={}):
self._root = {}
self._commands = {}
for cmd, func in commands:
self[cmd] = func
def _lookup(self, line):
parts = line.split(' ')
found = None
found_container = None
container = self._root
command_parts = 0
for i, part in enumerate(parts):
if part not in container:
return found_container, found, parts[command_parts:]
container = container[part]
if None in container:
found_container = container
found = container[None]
command_parts = i + 1
return found_container, found, parts[command_parts:]
def __setitem__(self, cmd, func):
container = self._root
parts = cmd.split(' ')
for part in parts:
container = container.setdefault(part, {})
if None in container:
raise ValueError('Command %s already exists' % cmd)
container[None] = func
self._commands[cmd] = func
def __getitem__(self, line):
return self._lookup(line)[1:]
def __contains__(self, item):
cmd, args = self[item]
return cmd is not None and not args
def __delitem__(self, cmd):
if cmd not in self:
raise KeyError(cmd)
container = self._lookup(cmd)[0]
del container[None]
del self._commands[cmd]
def __iter__(self):
return iter(self._commands)
def __len__(self):
return len(self._commands)
def __nonzero__(self):
return bool(self._commands)
def iterkeys(self):
return self._commands.iterkeys()
def iteritems(self):
return self._commands.iteritems()
def itervalues(self):
return self._commands.itervalues()
def __repr__(self):
return '<CommandStorage(%r)>' % self._commands.keys()
The full code (with a doctest) is in this gist as the doctest is not really relevant for the question