__eq__

__eq__(self, other)
Returns: bool · Added in vPython 2.1 · Updated March 18, 2026 · Dunder Methods
equality comparison dunder-methods oop

Overview

The __eq__ method defines the behavior of the equality operator (==) for your class. By default, Python compares objects by identity (whether they are the same object in memory), which is the behavior for all user-defined classes unless you override __eq__.

Signature

def __eq__(self, other):
    # Return True if self equals other, False otherwise
    # Return NotImplemented to fall back to the other object's __eq__

Basic Example

class Person:
    def __init__(self, name, age):
        self.name = name
        self.age = age

    def __eq__(self, other):
        if isinstance(other, Person):
            return self.age == other.age
        return False

john = Person("John", 30)
jane = Person("Jane", 30)

print(john == jane)  # True - same age
# output: True

The __ne__ Method

The __ne__ method defines behavior for the not-equal operator (!=). In Python 3, if you define __eq__ but not __ne__, Python automatically derives __ne__ as the negation of __eq__.

class Point:
    def __init__(self, x, y):
        self.x = x
        self.y = y

    def __eq__(self, other):
        if isinstance(other, Point):
            return self.x == other.x and self.y == other.y
        return False

p1 = Point(1, 2)
p2 = Point(1, 2)
p3 = Point(3, 4)

print(p1 == p2)  # True
# output: True
print(p1 != p3)  # True
# output: True

Comparison Fallback Order

When Python evaluates a == b:

  1. First, Python tries a.__eq__(b)
  2. If that returns NotImplemented, Python tries b.__eq__(a)
  3. If both return NotImplemented, objects are compared by identity

Returning NotImplemented tells Python to try the other object’s method:

class Money:
    def __init__(self, amount):
        self.amount = amount

    def __eq__(self, other):
        if isinstance(other, Money):
            return self.amount == other.amount
        return NotImplemented  # Let other try

dollar = Money(100)
cents = Money(10000)

print(dollar == cents)  # Depends on cents.__eq__

Important Gotchas

1. Always check the type

Never assume other has the same attributes:

# Wrong - will raise AttributeError
def __eq__(self, other):
    return self.age == other.age  # Fails if other has no age

# Correct - check type first
def __eq__(self, other):
    if not isinstance(other, Person):
        return False
    return self.age == other.age

2. __eq__ and __hash__

This is intentional behavior by design, not a bug. If you override __eq__, Python sets __hash__ to None by default. This makes your objects unhashable (cannot be used in sets or as dictionary keys), which prevents inconsistent behavior when objects that compare equal have different hash values:

class Person:
    def __init__(self, name):
        self.name = name

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

# This will fail - Person is now unhashable
# person = Person("John")
# {person}  # TypeError: unhashable type 'Person'

This happens because Python assumes that if two objects are equal, they should have the same hash value. By setting __hash__ to None, Python prevents you from accidentally violating this contract. To make objects hashable again, explicitly define __hash__:

class Person:
    def __init__(self, name):
        self.name = name

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

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

person = Person("John")
print({person})  # Works
# output: {<__main__.Person object at ...>}

3. Reflexive comparison

self == self should always return True. This works automatically in Python—you don’t need to handle it explicitly:

# This is always true in Python
print(5 == 5)  # True
# output: True

Comparison with Different Types

Python allows comparing objects of different types:

class Wrapper:
    def __init__(self, value):
        self.value = value

    def __eq__(self, other):
        if isinstance(other, Wrapper):
            return self.value == other.value
        if isinstance(other, (int, float)):
            return self.value == other
        return False

w = Wrapper(42)
print(w == 42)       # True
# output: True
print(w == "hello")  # False
# output: False

Return Values

The __eq__ method should return a boolean (True or False), or NotImplemented to indicate that the comparison is not handled. It should not raise exceptions under normal circumstances—return False instead when objects cannot be compared.

Summary

  • Define __eq__ to customize equality comparison for your objects
  • Return NotImplemented for unsupported types to allow reverse comparison
  • If you define __eq__ without __hash__, objects become unhashable by design
  • Python 3 automatically derives __ne__ from __eq__ if you don’t define it
  • Always check types before comparing attributes to avoid AttributeError

See Also

  • hash() — Returns the hash value of an object; related to __eq__ since defining __eq__ makes objects unhashable by default
  • dunder-str — Defines string representation; another common dunder method for customizing object behavior
  • id() — Returns the identity of an object; what equality falls back to when __eq__ is not defined