Summary: in this tutorial, you’ll learn about the Python hash() function and how to override the __hash__
method in a custom class.
Introduction to the Python hash function
Let’s start with a simple example.
First, define the Person
class with the name
and age
attributes:
class Person:
def __init__(self, name, age):
self.name = name
self.age = age
Code language: Python (python)
Second, create two instances of the Person
class:
p1 = Person('John', 22)
p2 = Person('Jane', 22)
Code language: Python (python)
Third, show the hashes of the p1
and p2
objects:
print(hash(p1))
print(hash(p2))
Code language: Python (python)
Output:
110373112736
110373572343
Code language: Python (python)
The hash()
function accepts an object and returns the hash value as an integer. When you pass an object to the hash()
function, Python will execute the __hash__
special method of the object.
It means that when you pass the p1
object to the hash()
function:
hash(p1)
Code language: Python (python)
Python will call the __hash__
method of the p1
object:
p1.__hash__()
Code language: Python (python)
By default, the __hash__
uses the object’s identity and the __eq__
returns True
if two objects are the same. To override this default behavior, you can implement the __eq__
and __hash__
.
If a class overrides the __eq__
method, the objects of the class become unhashable. This means that you won’t able to use the objects in a mapping type. For example, you will not able to use them as keys in a dictionary or elements in a set.
The following Person
class implements the __eq__
method:
class Person:
def __init__(self, name, age):
self.name = name
self.age = age
def __eq__(self, other):
return isinstance(other, Person) and self.age == other.age
Code language: Python (python)
If you attempt to use the Person
object in a set, you’ll get an error. For example:
members = {
Person('John', 22),
Person('Jane', 22)
}
Code language: Python (python)
Python issues the following error:
TypeError: unhashable type: 'Person'
Code language: Python (python)
Also, the Person’s object loses hashing because if you implement __eq__
, the __hash__
is set to None
. For example:
hash(Person('John', 22))
Code language: Python (python)
Error:
TypeError: unhashable type: 'Person'
Code language: Python (python)
To make the Person
class hashable, you also need to implement the __hash__
method:
class Person:
def __init__(self, name, age):
self.name = name
self.age = age
def __eq__(self, other):
return isinstance(other, Person) and self.age == other.age
def __hash__(self):
return hash(self.age)
Code language: Python (python)
Now, you have the Person
class that supports equality based on age
and is hashable.
To make the Person
work well in data structures like dictionaries, the hash of the class should remain immutable. To do it, you can make the age
attribute of the Person
class a read-only property:
class Person:
def __init__(self, name, age):
self.name = name
self._age = age
@property
def age(self):
return self._age
def __eq__(self, other):
return isinstance(other, Person) and self.age == other.age
def __hash__(self):
return hash(self.age)
Code language: Python (python)
Summary
- By default,
__hash__
uses the id of objects and__eq__
uses theis
operator for comparisons. - If you implement
__eq__
, Python sets__hash__
toNone
unless you implement__hash__
.