ProgrammingMiddle Python Developer

What defines the behavior of the comparison operator '==' and the __eq__ method in Python? How can the comparison behavior be modified for custom classes?

Pass interviews with Hintsage AI assistant

Answer.

Background:

In Python, object comparison by value occurs through the '==' operator, which internally calls the eq method. The default behavior of this method is inherited from object, and it compares the identity of objects (for most classes).

Problem:

When we want instances of custom classes to be meaningfully compared (for example, two different Person objects with the same set of data considered equal), the standard behavior is insufficient — we need to explicitly define how the comparison occurs.

Solution:

To change the behavior of '==', it is necessary to override the eq method in your own class. If the class should be hashable, it will also require overriding hash.

Example code:

class Person: def __init__(self, name, age): self.name = name self.age = age def __eq__(self, other): if not isinstance(other, Person): return NotImplemented return self.name == other.name and self.age == other.age p1 = Person("Ann", 25) p2 = Person("Ann", 25) print(p1 == p2) # True

Key features:

  • '==' calls eq.
  • When comparing objects without eq, their identity (id) will be compared.
  • For proper operation with sets/dictionaries, hash should also be implemented.

Tricky questions.

Is the comparison '==' always symmetric for objects of different types?

Not necessarily — if the first object returns NotImplemented, the reverse comparison will be invoked. Otherwise, it may result in asymmetry.

class A: def __eq__(self, other): return True class B: pass print(A() == B()) # True print(B() == A()) # False

If eq is not implemented, how will instances of the same custom class be compared?

Their id (identity in memory, not attribute values) will be compared.

class Foo: def __init__(self, x): self.x = x f1 = Foo(5) f2 = Foo(5) print(f1 == f2) # False

Can eq be defined without hash for objects that should be dictionary keys?

No. If eq is modified, it is also advisable to define hash, otherwise, the object will become unhashable (TypeError when used as a key).

class Foo: def __eq__(self, other): return True # hash is inherited from object, but behavior will be unpredictable # Better to explicitly define __hash__

Common mistakes and anti-patterns

  • Implementing eq without hash where dict/set keys are needed.
  • Error when comparing with objects of different types (should return NotImplemented, not False).
  • Inconsistent definitions of eq and hash, leading to incorrect behavior in hash structures.

Real-life example

Negative case

In designing the ValueObject class in a team, they overlooked that they implemented only eq, but not hash. When trying to use the object as a key in a dictionary or an element in a set, a TypeError exception occurred.

Pros:

Quick adoption of custom comparison.

Cons:

Inability to use objects in sets and dictionaries, difficulties in debugging.

Positive case

In another project, developers explicitly implemented both methods — eq and hash, strictly following the rule: if two objects are equal by eq, their hashes must match.

Pros:

Correct operation of hash structures, consistent behavior, ease of maintenance.

Cons:

Loss of flexibility: equal objects by values are indistinguishable in hash containers.