Python object equality: id vs value comparison

Demonstrates the difference between default identity comparison and custom equality, with a value-based class implementing __eq__ and __hash__.

Easy Python 3.9+ Aug 9, 2026 OOP & classes 12 views 0 copies

Python code

33 lines
Python 3.9+
import copy


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


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

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

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

    def __repr__(self):
        return f"ValueId({self.name!r})"


if __name__ == "__main__":
    a = copy.deepcopy(IdOnly("x"))
    b = copy.deepcopy(IdOnly("x"))
    print("id-only:", a == b, "| id(a) == id(b):", id(a) == id(b))

    c = ValueId("x")
    d = copy.deepcopy(ValueId("x"))
    print("value-based:", c == d, "| id(c) == id(d):", id(c) == id(d))

    e = ValueId("x")
    print("hash consistency:", hash(c) == hash(e), "| dict lookup:", {c: "same value"} [ValueId("x")])

Output

stdout
id-only: False | id(a) == id(b): False
value-based: True | id(c) == id(d): False
hash consistency: True | dict lookup: same value

How it works

By default, Python compares objects by identity (is), not value. To make two separate objects with the same data compare equal, you override __eq__. When you do, you should also override __hash__ to keep objects usable as dict keys; two equal objects must have the same hash. copy.deepcopy creates distinct objects, so id-only comparison returns False even for identical data. The custom __eq__ checks type and field equality, making value-based comparison return True.

Common mistakes

  • Forgetting to implement `__hash__` when overriding `__eq__`, breaking hash-based collections
  • Comparing objects with `==` expecting value equality without defining `__eq__`
  • Using mutable attributes in `__hash__` can lead to inconsistent hashing

Variations

  1. Use `functools.total_ordering` to auto-fill comparison operators from `__eq__` and `__lt__`
  2. Implement `__eq__` with a base class to share equality logic across subclasses

Real-world use cases

  • Custom classes used as dict keys, like caching objects by their data
  • Domain models where two records with identical fields should be considered the same
  • Test assertions that compare value objects regardless of memory location

Sponsored

Run this sample

Open the browser IDE to tweak the example and see results without installing anything.

Open editor

More from OOP & classes

Related tutorials and quizzes for this topic.