I got a problem with python 2.7 recently:
class A(object):
def __init__(self, v):
self.v = v
def __eq__(self, other):
return self.v == other.v
a1 = A(1)
a2 = A(1)
So:
print a1 == a2 # True
And:
d = {a1: 1}
print a2 in d.keys() # True
But:
print a2 in d # False
The question is what's the main difference between a2 ind.keys() and a2 in d? How can I get a2 in d is True?
In Python 2.7, dict.keys returns a list of keys and a2 in d.keys() will be iterating all the keys linearly to find if a2 is in the list.
But a2 in d will be just doing a O(1) lookup, based on the hash value of the object a2, in the dictionary to see if the key a2 is in d.
But in your case, problem is entirely different. Quoting official documentation,
If a class does not define a
__cmp__()or__eq__()method it should not define a__hash__()operation either; if it defines__cmp__()or__eq__()but not__hash__(), its instances will not be usable in hashed collections. If a class defines mutable objects and implements a__cmp__()or__eq__()method, it should not implement__hash__(), since hashable collection implementations require that a object’s hash value is immutable (if the object’s hash value changes, it will be in the wrong hash bucket).
Since you haven't explicitly defined __hash__ function, you are breaking the contract between them and __hash__ uses the default hashing based on the id of the object, which will be different for both a1 and a2. So even though a1 and a2 are similar, hashing objects will treat them as two different objects, as their hash values are different.
To fix this, you need to define __hash__ function, like this
class A(object):
def __init__(self, v):
self.v = v
def __eq__(self, other):
return self.v == other.v
def __hash__(self):
return hash(self.v)
a1 = A(1)
a2 = A(1)
d = {a1: 1}
print a2 in d.keys() # True
print a2 in d # True
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With