from weakref import ref, WeakKeyDictionary, WeakValueDictionary
class Id:
def __init__(self, key):
self._id = id(key)
#self._ref = ref(key)
def __hash__(self):
# NOTE Could also be hash((self._id, id(self._ref))), but is only really
# making a difference when entry deletion is delayed (iteration guards).
return self._id
def __eq__(self, other):
return self._id == other._id #and self._ref() is other._ref()
class WeakUnhashableKeyDictionary:
def __init__(self, *args, **kwargs):
# TODO Do something to initialize given args and kwargs.
self.keys = WeakValueDictionary()
self.values = WeakKeyDictionary()
def __getitem__(self, key):
return self.values.__getitem__(Id(key))
def get(self, key, default = None, /):
return self.values.get(Id(key), default = default)
def __setitem__(self, key, value):
_id = Id(key)
# NOTE This works because key holds on _id iif key exists,
# and _id holds on value iif _id exists. Transitivity. QED.
# Because key is only stored as a value, it does not need to be hashable.
self.keys.__setitem__(_id, key)
self.values.__setitem__(_id, value)
def __delitem__(self, key):
self.keys.__delitem__(Id(key))
self.values.__delitem__(Id(key))
def __iter__(self):
return map(lambda _id: self.keys[_id], self.values)
class Key:
__hash__ = None
d = WeakUnhashableKeyDictionary()
l = [Key(), Key(), Key()]
d[l[0]] = 1
d[l[1]] = 2
print(d[l[0]])
print(d[l[1]])
print(d.get(l[2]))
for k in d:
l.remove(k)
try:
print(d[Key()])
print('False match detected!')
except KeyError:
pass
ZnJvbSB3ZWFrcmVmIGltcG9ydCByZWYsIFdlYWtLZXlEaWN0aW9uYXJ5LCBXZWFrVmFsdWVEaWN0aW9uYXJ5CgpjbGFzcyBJZDoKICAgIGRlZiBfX2luaXRfXyhzZWxmLCBrZXkpOgogICAgICAgIHNlbGYuX2lkID0gaWQoa2V5KQogICAgICAgICNzZWxmLl9yZWYgPSByZWYoa2V5KQogICAgZGVmIF9faGFzaF9fKHNlbGYpOgogICAgCSMgTk9URSBDb3VsZCBhbHNvIGJlIGhhc2goKHNlbGYuX2lkLCBpZChzZWxmLl9yZWYpKSksIGJ1dCBpcyBvbmx5IHJlYWxseQogICAgCSMgbWFraW5nIGEgZGlmZmVyZW5jZSB3aGVuIGVudHJ5IGRlbGV0aW9uIGlzIGRlbGF5ZWQgKGl0ZXJhdGlvbiBndWFyZHMpLgogICAgICAgIHJldHVybiBzZWxmLl9pZAogICAgZGVmIF9fZXFfXyhzZWxmLCBvdGhlcik6CiAgICAgICAgcmV0dXJuIHNlbGYuX2lkID09IG90aGVyLl9pZCAjYW5kIHNlbGYuX3JlZigpIGlzIG90aGVyLl9yZWYoKQoKY2xhc3MgV2Vha1VuaGFzaGFibGVLZXlEaWN0aW9uYXJ5OgogICAgZGVmIF9faW5pdF9fKHNlbGYsICphcmdzLCAqKmt3YXJncyk6CiAgICAgICAgIyBUT0RPIERvIHNvbWV0aGluZyB0byBpbml0aWFsaXplIGdpdmVuIGFyZ3MgYW5kIGt3YXJncy4KICAgICAgICBzZWxmLmtleXMgPSBXZWFrVmFsdWVEaWN0aW9uYXJ5KCkKICAgICAgICBzZWxmLnZhbHVlcyA9IFdlYWtLZXlEaWN0aW9uYXJ5KCkKCiAgICBkZWYgX19nZXRpdGVtX18oc2VsZiwga2V5KToKICAgICAgICByZXR1cm4gc2VsZi52YWx1ZXMuX19nZXRpdGVtX18oSWQoa2V5KSkKICAgICAgICAKICAgIGRlZiBnZXQoc2VsZiwga2V5LCBkZWZhdWx0ID0gTm9uZSwgLyk6CiAgICAgICAgcmV0dXJuIHNlbGYudmFsdWVzLmdldChJZChrZXkpLCBkZWZhdWx0ID0gZGVmYXVsdCkKICAgIAogICAgZGVmIF9fc2V0aXRlbV9fKHNlbGYsIGtleSwgdmFsdWUpOgogICAgICAgIF9pZCA9IElkKGtleSkKICAgICAgICAjIE5PVEUgVGhpcyB3b3JrcyBiZWNhdXNlIGtleSBob2xkcyBvbiBfaWQgaWlmIGtleSBleGlzdHMsCiAgICAgICAgIyBhbmQgX2lkIGhvbGRzIG9uIHZhbHVlIGlpZiBfaWQgZXhpc3RzLiBUcmFuc2l0aXZpdHkuIFFFRC4KICAgICAgICAjIEJlY2F1c2Uga2V5IGlzIG9ubHkgc3RvcmVkIGFzIGEgdmFsdWUsIGl0IGRvZXMgbm90IG5lZWQgdG8gYmUgaGFzaGFibGUuCiAgICAgICAgc2VsZi5rZXlzLl9fc2V0aXRlbV9fKF9pZCwga2V5KQogICAgICAgIHNlbGYudmFsdWVzLl9fc2V0aXRlbV9fKF9pZCwgdmFsdWUpCgogICAgZGVmIF9fZGVsaXRlbV9fKHNlbGYsIGtleSk6CiAgICAgICAgc2VsZi5rZXlzLl9fZGVsaXRlbV9fKElkKGtleSkpCiAgICAgICAgc2VsZi52YWx1ZXMuX19kZWxpdGVtX18oSWQoa2V5KSkKICAgICAgICAKICAgIGRlZiBfX2l0ZXJfXyhzZWxmKToKICAgIAlyZXR1cm4gbWFwKGxhbWJkYSBfaWQ6IHNlbGYua2V5c1tfaWRdLCBzZWxmLnZhbHVlcykKCmNsYXNzIEtleToKICAgIF9faGFzaF9fID0gTm9uZQoKZCA9IFdlYWtVbmhhc2hhYmxlS2V5RGljdGlvbmFyeSgpCmwgPSBbS2V5KCksIEtleSgpLCBLZXkoKV0KZFtsWzBdXSA9IDEKZFtsWzFdXSA9IDIKCnByaW50KGRbbFswXV0pCnByaW50KGRbbFsxXV0pCnByaW50KGQuZ2V0KGxbMl0pKQoKZm9yIGsgaW4gZDoKICAgIGwucmVtb3ZlKGspCiAgICB0cnk6CiAgICAgICAgcHJpbnQoZFtLZXkoKV0pCiAgICAgICAgcHJpbnQoJ0ZhbHNlIG1hdGNoIGRldGVjdGVkIScpCiAgICBleGNlcHQgS2V5RXJyb3I6CiAgICAgICAgcGFzcw==