A dictionary key needs a stable hash and equality relation for as long as that key remains in the mapping.
Python interview: mutating a hash key breaks dictionary lookup assumptions
Operation contract
The intentionally unsafe ReceiptKey hashes its mutable identifier. After insertion, changing that identifier can make a normal lookup fail even though iterating the dictionary still shows the same object. The fixture prints an observed failed lookup for small fixed strings; hash collisions or a different hash seed could make that particular outcome differ, so the dependable rule is the violated key contract, not an asserted universal miss. The safe alternative uses an immutable tuple of validated fields.
Failure and ownership boundary
This class is a failure demonstration, never a pattern for production keys. If the key identifier can change, remove and reinsert under a new immutable value rather than mutating an object already owned by a mapping. Python hash and equality: immutable dictionary keys and Python dataclasses: frozen fields require an immutable value model explain the underlying contract.
Working program
class ReceiptKey:
def __init__(self, identifier):
self.identifier = identifier
def __hash__(self):
return hash(self.identifier)
def __eq__(self, other):
return type(other) is ReceiptKey and self.identifier == other.identifier
key = ReceiptKey("receipt-41")
ledger = {key: 125}
key.identifier = "receipt-42"
print("stored object:", next(iter(ledger)) is key)
print("stable replacement:", {("receipt-42",): 125}[("receipt-42",)])Output
stored object: True
stable replacement: 125Costs and limits
Dictionary operations are expected O(1) for ordinary stable keys, with collision and resizing qualifications. Violating the hash invariant makes lookup behavior unreliable; this demonstration deliberately avoids asserting a specific lookup result.
Common Mistakes
- Never mutate fields used by __hash__ while the key is stored.
- Finding the key by iteration does not mean hash-based lookup still works.
Connected lessons
Python hash and equality: immutable dictionary keys, Python dataclasses: frozen fields require an immutable value model, Python dictionaries: insertion order and duplicate-key replacement.
