Representing and Comparing Objects · practice
Hash Only Stable Values
Defining __eq__ changed something quietly. Try putting an equal
class Points:
def __init__(self, amount):
self.amount = amount
def __eq__(self, other):
if not isinstance(other, Points):
return NotImplemented
return self.amount == other.amount
{Points(3)}
Python reports TypeError: unhashable type: 'Points'.
Equality and hashing must agree
Sets and __eq__ was defined, identity supplied both equality and hashing, so they agreed.
A content-based __eq__ breaks that agreement. Python disables hashing instead of allowing a set to lose track of equal values.
Why does defining __eq__ without a matching __hash__ make this class unusable as a dictionary key?
Restore hashing only for stable values
Define __hash__ over exactly the state equality compares:
The read-only property keeps the supported public interface stable. If amount changed after insertion, its hash would point to a different place and membership lookup could fail while the object was still present. A leading underscore is still a convention, not enforcement; Chapter 8 introduces a frozen value that Python itself refuses to mutate.
For several compared attributes, hash the same
def __hash__(self):
return hash((self.prompt, self.answer, self.points))
Which class is safe to hash by its contents?
Hashing is not a reward every value needs. Add it only when sets or
The exercise makes Points and Question safely hashable. Ordering is a different design decision, handled next.
Task
Make the two read-only values safely hashable.
Give Points an __eq__ and matching __hash__ over amount.
Give Question an __eq__ and matching __hash__ over prompt, answer, and points.
Both equality NotImplemented for another type. Do not add ordering methods yet.