Skip to content

Instantly share code, notes, and snippets.

@KitB
Created February 2, 2016 03:38
Show Gist options
  • Save KitB/b6f59d2eccac0af5a931 to your computer and use it in GitHub Desktop.
Save KitB/b6f59d2eccac0af5a931 to your computer and use it in GitHub Desktop.
#!/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