fork(2) download
  1. from weakref import ref, WeakKeyDictionary, WeakValueDictionary
  2.  
  3. class Id:
  4. def __init__(self, key):
  5. self._id = id(key)
  6. #self._ref = ref(key)
  7. def __hash__(self):
  8. # NOTE Could also be hash((self._id, id(self._ref))), but is only really
  9. # making a difference when entry deletion is delayed (iteration guards).
  10. return self._id
  11. def __eq__(self, other):
  12. return self._id == other._id #and self._ref() is other._ref()
  13.  
  14. class WeakUnhashableKeyDictionary:
  15. def __init__(self, *args, **kwargs):
  16. # TODO Do something to initialize given args and kwargs.
  17. self.keys = WeakValueDictionary()
  18. self.values = WeakKeyDictionary()
  19.  
  20. def __getitem__(self, key):
  21. return self.values.__getitem__(Id(key))
  22.  
  23. def get(self, key, default = None, /):
  24. return self.values.get(Id(key), default = default)
  25.  
  26. def __setitem__(self, key, value):
  27. _id = Id(key)
  28. # NOTE This works because key holds on _id iif key exists,
  29. # and _id holds on value iif _id exists. Transitivity. QED.
  30. # Because key is only stored as a value, it does not need to be hashable.
  31. self.keys.__setitem__(_id, key)
  32. self.values.__setitem__(_id, value)
  33.  
  34. def __delitem__(self, key):
  35. self.keys.__delitem__(Id(key))
  36. self.values.__delitem__(Id(key))
  37.  
  38. def __iter__(self):
  39. return map(lambda _id: self.keys[_id], self.values)
  40.  
  41. class Key:
  42. __hash__ = None
  43.  
  44. d = WeakUnhashableKeyDictionary()
  45. l = [Key(), Key(), Key()]
  46. d[l[0]] = 1
  47. d[l[1]] = 2
  48.  
  49. print(d[l[0]])
  50. print(d[l[1]])
  51. print(d.get(l[2]))
  52.  
  53. for k in d:
  54. l.remove(k)
  55. try:
  56. print(d[Key()])
  57. print('False match detected!')
  58. except KeyError:
  59. pass
Success #stdin #stdout 0.04s 9624KB
stdin
Standard input is empty
stdout
1
2
None