andrefun
andrefun

Reputation: 79

What are the differences between key in dict & key in dict.keys()?

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

Answers (1)

thefourtheye
thefourtheye

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

Related Questions