Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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?

like image 876
andrefun Avatar asked Dec 14 '25 05:12

andrefun


1 Answers

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
like image 177
thefourtheye Avatar answered Dec 15 '25 20:12

thefourtheye



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!