On Fri, Feb 12, 2016 at 1:36 PM, Chris Barker chris.barker@noaa.gov wrote:
On Fri, Feb 12, 2016 at 12:27 PM, Andrew Barnert via Python-ideas python-ideas@python.org wrote:
I look forward to it. Next time I need some variation of this, even if it *isn't* the same variation you end up building, the fact that there's a potential de facto standard for what to call the ".inv" or whatever still helps me, right?
yeah, though I'm not sure I like that name... (can't think of a better one right now, though).
But what I would like is for the "inverse" to be available as an object itself, so:
my_double_dict = DoubleDict( ( (1:'a'), (2:'b'), (3:'c) ) ) my_inverse = my_double_dict.inv
my_double_dict[1] == 'a' my_inverse['a'] == 1
i.e you now have two objects, which are essentially the same object, but with inverse referencing semantics.
I have some unpublished (lightly tested) code that basically does this (inspired by Guava's BiMap).
class BiDict(dict):
def __init__(self, *args, **kwargs): self._inverse = _BiDictInverse(self) self._super_inverse = super(BiDict, self._inverse) self.update(*args, **kwargs)
@property def inverse(self): return self._inverse
def __repr__(self): return 'BiDict(%s)' % super().__repr__()
def __setitem__(self, key, value): if value in self._inverse and self._inverse[value] != key: raise ValueError( '%r already bound to %r' % (value, self._inverse[value])) if key in self: self._super_inverse.__delitem__(self[key]) super().__setitem__(key, value) self._super_inverse.__setitem__(value, key)
def __delitem__(self, key): self._super_inverse.__delitem__(self[key]) super().__delitem__(key)
def clear(self): super().clear() self._super_inverse.clear()
def pop(self, key, *args): key_was_present = key in self value = super().pop(key, *args) if key_was_present: self._super_inverse.__delitem__(value) return value
def popitem(self): (key, value) = super().popitem() self._super_inverse.__delitem__(value) return (key, value)
def setdefault(self, key, *args): key_was_present = key in self value = super().setdefault(key, *args) if not key_was_present: self._super_inverse.__setitem__(value, key) return value
def update(self, *args, **kwargs): if len(args) > 1: raise TypeError( 'update expected at most 1 arguments, got %d' % len(args)) if args and hasattr(args[0], 'keys'): for key in args[0]: self[key] = args[0][key] elif args: for key, value in args[0]: self[key] = value for key in kwargs: self[key] = kwargs[key]
class _BiDictInverse(BiDict):
def __init__(self, forward_dict): self._inverse = forward_dict self._super_inverse = super(BiDict, self._inverse)