Прочитав комментарий Гленна Мейнарда к ответу, который заставил меня удалить этот, я решил воскресить его. Он использует обычный список для хранения индексов и поэтому будет иметь тот же O (1) доступ.
Вот мое мнение. Обработка ошибок, возможно, могла бы быть улучшена, но я не хотел слишком загромождать код. Я не знаю, как исходный код обрабатывал его, но почему бы не пойти дальше и обработать фрагменты. Мы можем обрабатывать назначения слайсов только для слайсов, которые не создают новые ключи (то есть не меняют количество элементов), но мы можем обрабатывать произвольные поиски слайсов. Обратите внимание, что он также эффективно запрещает целочисленные ключи. Вот небольшая демонстрация в действии.
class IndexedDict(object):
def __init__(self, *args, **kwargs):
d = dict(*args, **kwargs)
self._keys = d.keys() # list(d.keys()) in python 3.1
self._d = d
def __getitem__(self, item):
if isinstance(item, int):
key = self._keys[item]
return self._d[key]
elif isinstance(item, slice):
keys = self._keys[item]
return tuple(self._d[key] for key in keys)
else:
return self._d[key]
def __setitem__(self, item, value):
if isinstance(item, int):
key = self._keys[item]
self._d[key] = value
elif isinstance(item, slice):
# we only handle slices that don't require the creation of
# new keys.
keys = self._keys[item]
if not len(keys) == len(value):
raise ValueError("Complain here")
for key, v in zip(keys, value):
self._d[key] = v
else:
self._d[item] = value
if item not in self._keys:
# This is the only form that can create a new element
self._keys.append(item)
def __delitem__(self, item):
if isinstance(item, int):
key = self._keys[item]
del self._keys[item]
del self._d[key]
elif isinstance(item, slice):
keys = self._keys[item]
del self._keys[item]
for key in keys:
del self._d[key]
else:
del self._d[item]
self._keys.remove(item)
def __contains__(self, item):
if isinstance(item, int):
return i < len(self._keys)
else:
return i in self._d
# Just for debugging. Not intended as part of API.
def assertions(self):
assert len(self._d) == len(self._keys)
assert set(self._d.keys()) == set(self._keys)
Есть еще кое-что для реализации. keys
, items
, iteritems
, update
и т. Д., Но они не должны быть слишком жесткими. Просто работайте с self._keys
и используйте списочные вычисления и выражения генератора. Например, iteritems
- это просто (self._d[key] for key in self._keys)
. Для обновления я бы просто удостоверился, что вы имеете дело с объектами, похожими на диктовку, а затем обновите self._keys
как self._keys += [key for key in other.keys() if key not in self._keys]
. Я мог бы пойти так далеко, чтобы определить __add__
практически таким же образом.