Singledispatch chooses a registered implementation from the runtime type of the first positional argument.
Python singledispatch: dispatch follows the first argument’s type
Operation contract
The default receipt encoder rejects unsupported types. The integer implementation has an exact-type and amount check, while a Boolean registration explicitly rejects bool before its int inheritance can select the numeric route. A text implementation only accepts a small ASCII decimal representation and forwards the converted value to the same integer rule. This keeps two accepted input formats behind one amount contract.
Failure and ownership boundary
Dispatch is not schema validation. Registering int does not imply that every int subclass or every integer magnitude is a valid amount. Other arguments do not participate in singledispatch selection. A broad object registration changes the fallback, and extension registration is a trusted code action. Python first-class functions: dispatch through an explicit operation registry, Python type conversion: parsing success is not field validity and Python __init_subclass__: validate declarations without a custom metaclass explain those boundaries.
Working program
from functools import singledispatch
@singledispatch
def encoded_amount(amount):
raise ValueError("unsupported representation")
@encoded_amount.register(int)
def encode_integer(amount):
if type(amount) is not int or not 0 <= amount <= 1000:
raise ValueError("bounded exact integer")
return f"minor:{amount}"
@encoded_amount.register(bool)
def reject_boolean(amount):
raise ValueError("boolean amount")
@encoded_amount.register(str)
def encode_text(amount):
if not 1 <= len(amount) <= 4 or any(character not in "0123456789" for character in amount):
raise ValueError("ASCII amount")
return encode_integer(int(amount))
print(encoded_amount(125))
print(encoded_amount("75"))
for invalid in (True, 1.5, "-1"):
try:
encoded_amount(invalid)
except ValueError:
print("representation rejected")Output
minor:125
minor:75
representation rejected
representation rejected
representation rejectedCosts and limits
Initial dispatch may examine type relationships; subsequent dispatches can use cached decisions. This is not a fixed-cost promise for arbitrary class hierarchies. The four-character text cap bounds conversion work; formatting a general unbounded integer needs a separate cost policy.
Common Mistakes
- bool is an int subclass, so numeric registration needs a Boolean policy.
- singledispatch does not inspect all arguments or enforce annotated types.
Connected lessons
Python first-class functions: dispatch through an explicit operation registry, Python type conversion: parsing success is not field validity, Python __init_subclass__: validate declarations without a custom metaclass.
