| """Misc dict tools.""" |
| |
| __all__ = ["hashdict"] |
| |
| |
| # https://stackoverflow.com/questions/1151658/python-hashable-dicts |
| class hashdict(dict): |
| """ |
| hashable dict implementation, suitable for use as a key into |
| other dicts. |
| |
| >>> h1 = hashdict({"apples": 1, "bananas":2}) |
| >>> h2 = hashdict({"bananas": 3, "mangoes": 5}) |
| >>> h1+h2 |
| hashdict(apples=1, bananas=3, mangoes=5) |
| >>> d1 = {} |
| >>> d1[h1] = "salad" |
| >>> d1[h1] |
| 'salad' |
| >>> d1[h2] |
| Traceback (most recent call last): |
| ... |
| KeyError: hashdict(bananas=3, mangoes=5) |
| |
| based on answers from |
| http://stackoverflow.com/questions/1151658/python-hashable-dicts |
| |
| """ |
| |
| def __key(self): |
| return tuple(sorted(self.items())) |
| |
| def __repr__(self): |
| return "{0}({1})".format( |
| self.__class__.__name__, |
| ", ".join("{0}={1}".format(str(i[0]), repr(i[1])) for i in self.__key()), |
| ) |
| |
| def __hash__(self): |
| return hash(self.__key()) |
| |
| def __setitem__(self, key, value): |
| raise TypeError( |
| "{0} does not support item assignment".format(self.__class__.__name__) |
| ) |
| |
| def __delitem__(self, key): |
| raise TypeError( |
| "{0} does not support item assignment".format(self.__class__.__name__) |
| ) |
| |
| def clear(self): |
| raise TypeError( |
| "{0} does not support item assignment".format(self.__class__.__name__) |
| ) |
| |
| def pop(self, *args, **kwargs): |
| raise TypeError( |
| "{0} does not support item assignment".format(self.__class__.__name__) |
| ) |
| |
| def popitem(self, *args, **kwargs): |
| raise TypeError( |
| "{0} does not support item assignment".format(self.__class__.__name__) |
| ) |
| |
| def setdefault(self, *args, **kwargs): |
| raise TypeError( |
| "{0} does not support item assignment".format(self.__class__.__name__) |
| ) |
| |
| def update(self, *args, **kwargs): |
| raise TypeError( |
| "{0} does not support item assignment".format(self.__class__.__name__) |
| ) |
| |
| # update is not ok because it mutates the object |
| # __add__ is ok because it creates a new object |
| # while the new object is under construction, it's ok to mutate it |
| def __add__(self, right): |
| result = hashdict(self) |
| dict.update(result, right) |
| return result |