0%

Representing and Comparing Objects · practice

Hash Only Stable Values

Defining __eq__ changed something quietly. Try putting an equal in a set:

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 locate an using a number called its hash. Equal objects must produce equal hashes. Before __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:

Try it

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 equality compares:

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 are part of the class’s real use, and only when the compared state cannot change.

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 return NotImplemented for another type. Do not add ordering methods yet.