What Makes an Object Hashable in Python and How Is Its Hash Computed?
An object is hashable in Python if it is immutable and implements __eq__, allowing it to serve as a dictionary key; the hash value is normally derived from the object's address unless __hash__ is overridden, and equal objects must share identical hash values, influencing dictionary indexing and collision handling.
By examining the underlying implementation of Python dictionaries, we discover that their speed and efficiency stem from hash tables, and hash values are the key factor that determines the index after mapping.
To compute an object's hash value, the object must be hashable. An object is hashable when it satisfies two conditions:
It is immutable, because a hash value must never change.
It implements the __eq__ method, so that objects with equal hash values can be compared for equality.
Objects meeting both criteria can be used as dictionary keys or set elements. Built‑in immutable types such as integers, floats, and strings are hashable. Mutable types like lists or dictionaries are not. A tuple is hashable only if every element inside it is hashable.
# key must be hashable; value can be any type
d = {1: 1, "xxx": [1, 2, 3], 3.14: 333}
# list is mutable → unhashable
try:
d = {[]: 123}
except TypeError as e:
print(e)
"""
unhashable type: 'list'
"""
# tuple is hashable
d = {(1, 2, 3): 123}
# tuple containing a list becomes unhashable
try:
d = {(1, 2, 3, []): 123}
except TypeError as e:
print(e)
"""
unhashable type: 'list'
"""Instances of a user‑defined class are hashable by default, with the hash derived from the object's memory address:
class Some:
pass
s1 = Some()
s2 = Some()
print(hash(s1), hash(s2))
"""
8744065697364 8744065697355
"""Python also allows overriding the hash function:
class Some:
def __hash__(self):
return 123
s1 = Some()
s2 = Some()
print(hash(s1), hash(s2))
"""
123 123
"""
print({s1: 1, s2: 2})
"""
{<__main__.Some object at 0x0000029C0ED045E0>: 1, <__main__.Some object at 0x0000029C5E116F20>: 2}
"""Because the two objects share the same hash, the dictionary would encounter a collision. Since the default __eq__ returns False, the collision is resolved by probing for a free slot, so both keys are stored.
If two objects are equal, their hash values must also be equal.
Note that if a class overrides __eq__ without also overriding __hash__, its instances become unhashable:
class Some:
def __eq__(self, other):
return True
try:
hash(Some())
except TypeError as e:
print(e)
"""
unhashable type: 'Some'
"""When __eq__ is overridden, equality is controlled by the custom method, but the default hash (based on address) may differ, leading to a contradiction: equal objects with different hashes are not allowed, so Python marks such objects as unhashable.
If both __eq__ and __hash__ are overridden to return the same constant, the objects become hashable but are considered equal, so a dictionary retains only one entry:
class Some:
def __eq__(self, other):
return True
def __hash__(self):
return 123
s1 = Some()
s2 = Some()
print({s1: 1, s2: 2})
"""
{<__main__.Some object at 0x00000202D7D945E0>: 2}
"""When __eq__ returns False but __hash__ returns the same value, both keys are kept, though a collision occurs and the dictionary re‑hashes to a new slot:
class Some:
def __eq__(self, other):
return False
def __hash__(self):
return 123
def __repr__(self):
return "Some Instance"
s1 = Some()
print(s1 == s1) # False
print({s1: 1, s1: 2})
"""
{Some Instance: 2}
"""
s2 = Some()
print({s1: 1, s2: 2})
"""
{Some Instance: 1, Some Instance: 2}
"""Dictionary key handling also demonstrates how different built‑in types interact:
d = {1: 123}
d[1.0] = 234
print(d) # {1: 234}
d[True] = 345
print(d) # {1: 345}Integers hash to themselves; a float ending with .0 is considered equal to the same integer, and bool is a subclass of int, so True equals 1. Consequently, inserting 1.0 or True updates the existing entry rather than creating a new key.
When setting a key, the dictionary first maps the key to an index in the hash‑index array. If the slot is empty, the key‑value pair is stored directly. If the slot is occupied, the stored index points to an entry in the key‑value array; the dictionary then compares the incoming key with the stored key. If they are not equal, it probes for another slot; if they are equal, it overwrites the value.
This process never modifies the key itself, which explains why in the previous example the key remains 1 even though the value changes.
Finally, a good hash function should distribute hash values uniformly across the hash space, making small differences in input produce large differences in hash output; the quality of the hash function directly affects hash‑table performance.
In summary, an object can be hashed if it is immutable and implements __eq__. Built‑in immutable objects provide __hash__ automatically. Custom classes are hashable by default via address‑based hashing, but overriding __eq__ without __hash__ makes them unhashable, while overriding both allows custom hash behavior that influences dictionary key collisions.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
Satori Komeiji's Programming Classroom
Python and Rust developer; I write about any topics you're interested in. Follow me! (#^.^#)
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
