Created
February 2, 2016 03:38
-
-
Save KitB/b6f59d2eccac0af5a931 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env python | |
# -*- coding: utf-8 -*- | |
import unittest | |
class ListDict(list): | |
""" List of dicts with rapid is-element-of operation for the whole thing. | |
(e.g. `(k, v) in list_dict`) | |
Keys and values must be hashable. | |
""" | |
def __init__(self, iterable=None): | |
if iterable is not None: | |
iterable = (_LD_Dict(self, item) for item in iterable) | |
else: | |
iterable = [] | |
self._super = super(ListDict, self) | |
self._super.__init__(iterable) | |
self.dirty = True | |
@property | |
def entries(self): | |
if self.dirty: | |
self._update_entries() | |
return self._entries | |
def _update_entries(self): | |
if not self.dirty: | |
return | |
self._entries = set().union(*(d.entries for d in self)) | |
self.dirty = False | |
def __setitem__(self, key, value): | |
self._super.__setitem__(key, _LD_Dict(self, value)) | |
self.dirty = True | |
def append(self, value): | |
self._super.append(_LD_Dict(self, value)) | |
self.dirty = True | |
def extend(self, values): | |
append = self.append # Does the interpreter already do this optimization? | |
for value in values: | |
append(value) | |
def __getitem__(self, key): | |
return self._super.__getitem__(key) | |
def __delitem(self, key): | |
self._super.__delitem__(key) | |
self.dirty = True | |
def __contains__(self, value): | |
return value in self.entries | |
def __repr__(self): | |
return '{%s}.entries = %s' % (list(self), self.entries) | |
class _LD_Dict(dict): | |
def __init__(self, parent, *args, **kwargs): | |
self.parent = parent | |
self._super = super(_LD_Dict, self) | |
self._super.__init__(*args, **kwargs) | |
self.entries = set(self.iteritems()) | |
def __setitem__(self, key, value): | |
try: | |
self.entries.remove((key, self[key])) | |
except KeyError: | |
pass | |
self.entries.add((key, value)) | |
self._super.__setitem__(key, value) | |
self.parent.dirty = True | |
def __delitem__(self, key): | |
self.entries.remove((key, self[key])) | |
self.parent.dirty = True | |
self._super.__delitem__(key) | |
_test_dict = {'blah': 'qwer'} | |
_test_pair = ('blah', 'qwer') | |
class Test_ListDict(unittest.TestCase): | |
def test_init(self): | |
ld = ListDict([_test_dict]) | |
self.assertIn(_test_pair, ld) | |
def test_setitem(self): | |
ld = ListDict([{'foo': 'bar'}]) | |
ld[0] = _test_dict | |
self.assertIn(_test_pair, ld) | |
def test_delitem(self): | |
ld = ListDict([_test_dict]) | |
del ld[0] | |
self.assertSetEqual(ld.entries, set()) | |
def test_append(self): | |
ld = ListDict() | |
ld.append(_test_dict) | |
self.assertIn(_test_pair, ld) | |
def test_extend(self): | |
ld = ListDict() | |
ld.extend([_test_dict]) | |
self.assertIn(_test_pair, ld) | |
def test_inner_setitem(self): | |
ld = ListDict([]) | |
ld.append({}) | |
ld[0]['blah'] = 'qwer' | |
self.assertIn(_test_pair, ld) | |
def test_inner_delitem(self): | |
ld = ListDict([_test_dict]) | |
del ld[0]['blah'] | |
self.assertSetEqual(ld.entries, set()) | |
def main(): | |
unittest.main() | |
if __name__ == '__main__': | |
main() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment