Skip to content

eq-without-hash (PLW1641)

Derived from the Pylint linter.

What it does

Checks for classes that implement __eq__ but not __hash__.

Why is this bad?

A class that implements __eq__ but not __hash__ will have its hash method implicitly set to None, regardless of if a superclass defines __hash__. This will cause the class to be unhashable, which will in turn cause issues when using instances of the class as keys in a dictionary or members of a set.

Example

class Person:
    def __init__(self):
        self.name = "monty"

    def __eq__(self, other):
        return isinstance(other, Person) and other.name == self.name

Use instead:

class Person:
    def __init__(self):
        self.name = "monty"

    def __eq__(self, other):
        return isinstance(other, Person) and other.name == self.name

    def __hash__(self):
        return hash(self.name)

In general, it is unsound to inherit a __hash__ implementation from a parent class while overriding the __eq__ implementation because the two must be kept in sync. However, an easy way to resolve this error in cases where it is sound is to explicitly set __hash__ to the parent class's implementation:

class Developer(Person):
    def __init__(self): ...

    def __eq__(self, other): ...

    __hash__ = Person.__hash__

References