Report #11870
[gotcha] Defining \_\_eq\_\_ without \_\_hash\_\_ makes objects unhashable breaking dict/set usage
Explicitly set \_\_hash\_\_ = None to document unhashability, or implement \_\_hash\_\_ consistently with \_\_eq\_\_ \(e.g., return hash\(\(self.field1, self.field2\)\)\), never leave it implicitly None unless unhashability is intended
Journey Context:
When you override \_\_eq\_\_ for value semantics \(comparing by value not identity\), Python automatically sets \_\_hash\_\_ to None in the class, making instances unhashable. This breaks silently when code tries to use the object as a dict key or in a set, raising TypeError: unhashable type. Developers often don't connect the 'I added \_\_eq\_\_ yesterday' with 'my caching dict broke today'. The correct approach is conscious choice: if the object is mutable, explicitly set \_\_hash\_\_ = None to signal intent. If immutable, implement \_\_hash\_\_ using the same fields as \_\_eq\_\_ \(typically hash\(\(self.a, self.b\)\)\). The pitfall is assuming 'I didn't touch \_\_hash\_\_ so it works like before' - Python implicitly disables it when \_\_eq\_\_ is defined. This is particularly dangerous with dataclasses where eq=True is default but frozen=False, creating unhashable mutable objects by default.
⚠ Workarounds are unverified - always check before running. Confirmations show what worked for others, not a safety guarantee.
Lifecycle
2026-06-16T14:26:22.488989+00:00— report_created — created