from weakref import ref, WeakKeyDictionary, WeakValueDictionary
class Id:
def __init__(self, key):
self._id = id(key)
self.keyref = ref(key)
def __hash__(self):
return self._id
def __eq__(self, other):
return self._id == other._id and self.keyref() is other.keyref()
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 __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))
class Key:
__hash__ = None
d = WeakUnhashableKeyDictionary()
l = [Key(), Key(), Key()]
d[l[0]] = 1
d[l[1]] = 2
for k in d.keys.values():
l.remove(k)
try:
print(d[Key()])
print('False match detected!')
except KeyError:
pass
ZnJvbSB3ZWFrcmVmIGltcG9ydCByZWYsIFdlYWtLZXlEaWN0aW9uYXJ5LCBXZWFrVmFsdWVEaWN0aW9uYXJ5CgpjbGFzcyBJZDoKICAgIGRlZiBfX2luaXRfXyhzZWxmLCBrZXkpOgogICAgICAgIHNlbGYuX2lkID0gaWQoa2V5KQogICAgICAgIHNlbGYua2V5cmVmID0gcmVmKGtleSkKICAgIGRlZiBfX2hhc2hfXyhzZWxmKToKICAgICAgICByZXR1cm4gc2VsZi5faWQKICAgIGRlZiBfX2VxX18oc2VsZiwgb3RoZXIpOgogICAgICAgIHJldHVybiBzZWxmLl9pZCA9PSBvdGhlci5faWQgYW5kIHNlbGYua2V5cmVmKCkgaXMgb3RoZXIua2V5cmVmKCkKCmNsYXNzIFdlYWtVbmhhc2hhYmxlS2V5RGljdGlvbmFyeToKICAgIGRlZiBfX2luaXRfXyhzZWxmLCAqYXJncywgKiprd2FyZ3MpOgogICAgICAgICMgVE9ETyBEbyBzb21ldGhpbmcgdG8gaW5pdGlhbGl6ZSBnaXZlbiBhcmdzIGFuZCBrd2FyZ3MuCiAgICAgICAgc2VsZi5rZXlzID0gV2Vha1ZhbHVlRGljdGlvbmFyeSgpCiAgICAgICAgc2VsZi52YWx1ZXMgPSBXZWFrS2V5RGljdGlvbmFyeSgpCgogICAgZGVmIF9fZ2V0aXRlbV9fKHNlbGYsIGtleSk6CiAgICAgICAgcmV0dXJuIHNlbGYudmFsdWVzLl9fZ2V0aXRlbV9fKElkKGtleSkpCiAgICAKICAgIGRlZiBfX3NldGl0ZW1fXyhzZWxmLCBrZXksIHZhbHVlKToKICAgICAgICBfaWQgPSBJZChrZXkpCiAgICAgICAgIyBOT1RFIFRoaXMgd29ya3MgYmVjYXVzZSBrZXkgaG9sZHMgb24gX2lkIGlpZiBrZXkgZXhpc3RzLAogICAgICAgICMgYW5kIF9pZCBob2xkcyBvbiB2YWx1ZSBpaWYgX2lkIGV4aXN0cy4gVHJhbnNpdGl2aXR5LiBRRUQuCiAgICAgICAgIyBCZWNhdXNlIGtleSBpcyBvbmx5IHN0b3JlZCBhcyBhIHZhbHVlLCBpdCBkb2VzIG5vdCBuZWVkIHRvIGJlIGhhc2hhYmxlLgogICAgICAgIHNlbGYua2V5cy5fX3NldGl0ZW1fXyhfaWQsIGtleSkKICAgICAgICBzZWxmLnZhbHVlcy5fX3NldGl0ZW1fXyhfaWQsIHZhbHVlKQoKICAgIGRlZiBfX2RlbGl0ZW1fXyhzZWxmLCBrZXkpOgogICAgICAgIHNlbGYua2V5cy5fX2RlbGl0ZW1fXyhJZChrZXkpKQogICAgICAgIHNlbGYudmFsdWVzLl9fZGVsaXRlbV9fKElkKGtleSkpCgpjbGFzcyBLZXk6CiAgICBfX2hhc2hfXyA9IE5vbmUKCmQgPSBXZWFrVW5oYXNoYWJsZUtleURpY3Rpb25hcnkoKQpsID0gW0tleSgpLCBLZXkoKSwgS2V5KCldCmRbbFswXV0gPSAxCmRbbFsxXV0gPSAyCgpmb3IgayBpbiBkLmtleXMudmFsdWVzKCk6CiAgICBsLnJlbW92ZShrKQogICAgdHJ5OgogICAgICAgIHByaW50KGRbS2V5KCldKQogICAgICAgIHByaW50KCdGYWxzZSBtYXRjaCBkZXRlY3RlZCEnKQogICAgZXhjZXB0IEtleUVycm9yOgogICAgICAgIHBhc3M=