Why is a dictionary key converted to an inherited class type?

My code looks something like this:

class SomeClass(str): pass some_dict = {'s':42} >>> type(some_dict.keys()[0]) str >>> s = SomeClass('s') >>> some_dict[s] = 40 >>> some_dict # expected: Two different keys-value pairs {'s': 40} >>> type(some_dict.keys()[0]) str 

Why did Python convert the s object to the string "s" when updating the some_dict dictionary?

+7
python dictionary class
source share
2 answers

While the value of the hash function is related, this is not the main factor. Equality is more important here. That is, objects can have the same hash value and not be equal, but equal objects must have the same hash value (although this is not strictly enforced). Otherwise, you will encounter some strange errors when using dict and set .

Since you did not define the __eq__ method on SomeClass , you inherit it on str . Built-in built-in Python is built-in to provide a subclass, so __eq__ returns true if the object would otherwise be equal if it did not have different types. eg. 's' == SomeClass('s') true. Thus, it is right and right that 's' and SomeClass('s') equivalent as keys to a dictionary.

To get the behavior you need, you must override the __eq__ dunder method to take into account the type. However, when you define a user equivalent, python stops giving you the __hash__ dunder automatic method, and you must also override it. But in this case, we can just reuse str.__hash__ .

 class SomeClass(str): def __eq__(self, other): return ( type(self) is SomeClass and type(other) is SomeClass and super().__eq__(other) ) __hash__ = str.__hash__ d = {'s': 1} d[SomeClass('s')] = 2 assert len(d) == 2 print(d) 

Fingerprints: {'s': 2, 's': 1}

+17
source share

This is a really good question. First, when put (key, value) is in a dict , it uses a hash function to get the hash value of the key and check for the presence of this hash code. If present, then dict compares the object with the same hash code. If two objects are equal ( __eq__(self, other) return True ), then it will update the value, so your code encounters this behavior.

This SomeClass is not even modified, so 's' and SomeClass('s') must have the same hash code, and 's'.__eq__(SomeClass('s')) will return True.

0
source share

All Articles