A hashable dictionary key needs a hash that remains stable during its lifetime, and equal keys must produce equal hashes.
Python hash and equality: immutable dictionary keys
Operation contract
The receipt key has two immutable fields and value-based equality supplied by a frozen dataclass. Separately constructed equal keys retrieve the same ledger entry. The stored amount is not part of the key. Keeping identity separate from changing state avoids losing an entry after a field used by its hash changes.
Failure and ownership boundary
Frozen dataclasses prevent their normal field assignment; they do not recursively freeze nested objects. This key uses only a string and an integer. A class that defines equality without a suitable hash becomes unhashable. Hash collisions are legal: dictionary lookup still compares candidate keys. Python dictionaries: insertion order and duplicate-key replacement and Python dataclasses: frozen fields require an immutable value model explain the surrounding rules.
Working program
from dataclasses import dataclass
@dataclass(frozen=True)
class ReceiptKey:
region: str
sequence: int
ledger = {ReceiptKey("DEL", 41): 1250}
lookup_key = ReceiptKey("DEL", 41)
print(ledger[lookup_key])
print(hash(lookup_key) == hash(ReceiptKey("DEL", 41)))
try:
ledger[["DEL", 41]] = 1250
except TypeError:
print("mutable list rejected as key")Output
1250
True
mutable list rejected as keyCosts and limits
Dictionary operations have expected constant lookup work under suitable hash behavior, but collisions can require more comparisons. Computing a key hash also has field-dependent cost. Do not persist Python hash values as stable cross-process identifiers.
Common Mistakes
- Equal keys must have equal hashes; unequal keys may also collide.
- A frozen wrapper can still contain unsuitable mutable fields.
Connected lessons
Python dictionaries: insertion order and duplicate-key replacement, Python dataclasses: frozen fields require an immutable value model, Python sets: membership and deduplication do not preserve input order.
Follow the ownership and update boundary
Python rich comparison: return NotImplemented for unsupported operands.
Check this related boundary
Python interview: mutating a hash key breaks dictionary lookup assumptions.
Trace the next boundary
Python interview: bool and int can address the same dictionary key.
Follow the integrity boundary
Python interview: a tuple can be unhashable when it contains a list.
