Reputation: 79
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
?
Upvotes: 3
Views: 507
Reputation: 239693
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
Upvotes: 7