I want to use some objects as keys for some dict, which are either unhashable, or hashable but I want to overwrite their __eq__
/__hash__
with the default object.__eq__
/object.__hash__
, i.e. namely a == b
iff a is b
.
(These objects could e.g. be numpy.ndarray
, torch.Tensor
, or other things, but I want to ask in general now.)
E.g.:
x = numpy.array([2,3,4])
d = {x: 5}
That would give the exception TypeError: unhashable type: 'numpy.ndarray'
.
Or:
x = torch.Tensor([2,3,4])
d = weakref.WeakKeyDictionary()
d[x] = 5
print(d[x])
That would give the exception RuntimeError: Boolean value of Tensor with more than one value is ambiguous
. (Which is quite misleading or unexpected. But I assume this is because it will do bool(__eq__(...))
internally. However, strangely, there is no such exception when I use a normal dict
here. Why?)
I could write a custom object wrapper to solve this, like:
class WrappedObject:
def __init__(self, orig):
self.orig = orig
def __eq__(self, other):
return object.__eq__(self.orig, other.orig)
def __ne__(self, other):
return object.__ne__(self.orig, other.orig)
def __hash__(self):
return object.__hash__(self.orig)
That would solve the first case. Now I can write:
x = numpy.array([2,3,4])
d = {WrappedObject(x): 5}
print(d[WrappedObject(x)]) # 5
Is there sth like WrappedObject
in some of the std lib?
The id
function has similar behavior, although it just returns an int
, and doesn't have a reference back to the original object. So for this example, I could write:
x = numpy.array([2,3,4])
d = {id(x): 5}
print(d[id(x)]) # 5
Note that this might be problematic! In case x
gets freed later on, then another object could theoretically be created which has the same id
, because id
is only guaranteed to be unique during the lifetime, not after its lifetime.
(Related question here, although the accepted answer exactly has this problem.)
This problem would not happen with WrappedObject
, as the reference is always kept alive.
Is there sth which would wrap dict
to automatically use sth like WrappedObject
under the hood? I.e. specifically I want that for all the keys, it only uses their identity for equality.
Now consider my second case, specifically WeakKeyDictionary
. I cannot use WrappedObject
, because the WrappedObject
itself is not kept alive, so all keys would immediately vanish:
x = torch.Tensor([2,3,4])
d = weakref.WeakKeyDictionary()
d[WrappedObject(x)] = 5
print(list(d.items())) # prints []
The only real solution I currently see is to reimplement WeakKeyDictionary
myself, using sth like WrappedRefObject
. Is there a better solution? Does this already exist in the std lib or elsewhere?