Python single dispatch (from functools.singledispatch) provides function overloading based on the type of the first argument. A single function name dispatches to different implementations depending on what type is passed, making type-specific behavior declarative and extensible without large if/elif chains.
Use single dispatch to handle different types elegantly, or to allow plugins to register handlers for new types.
This example shows function dispatch by type without conditional chains.
# run: python3 singledispatch.py # description: single dispatch for type-based function overloading from functools import singledispatch @singledispatch def process(arg): """Default implementation for unknown types.""" raise TypeError(f"Cannot process {type(arg)}") @process.register(int) def _(value: int): return value * 2 @process.register(str) def _(value: str): return value.upper() @process.register(list) def _(value: list): return sum(value) @process.register(dict) def _(value: dict): return len(value) # Dispatch based on argument type print(f"process(5) = {process(5)}") print(f"process('hello') = {process('hello')}") print(f"process([1, 2, 3]) = {process([1, 2, 3])}") print(f"process({{'a': 1, 'b': 2}}) = {process({'a': 1, 'b': 2})}") # Plugin system: register new types class Custom: def __init__(self, value): self.value = value @process.register(Custom) def _(obj: Custom): return obj.value print(f"process(Custom(42)) = {process(Custom(42))}") # Check registered types print(f"\nRegistered types: {process.registry}") # Dispatch with inheritance class Animal: pass class Dog(Animal): pass @singledispatch def speak(animal): print(f"Unknown animal: {animal}") @speak.register(Dog) def _(dog): print("Woof!") @speak.register(Animal) def _(animal): print("Generic animal sound") speak(Dog()) speak(Animal()) speak("not an animal") # uses default # Method dispatch (Python 3.8+) from functools import singledispatchmethod class Formatter: @singledispatchmethod def format(self, arg): raise TypeError(f"Cannot format {type(arg)}") @format.register(int) def _(self, value: int): return f"Integer: {value}" @format.register(str) def _(self, value: str): return f"String: {value}" fmt = Formatter() print(f"\nFormatter: {fmt.format(123)}") print(f"Formatter: {fmt.format('hello')}")
Default implementation:
@singledispatch decoratorRegistering handlers:
@func.register(type): register handler for typefunc.register(type, handler) syntaxType hierarchy:
Method dispatch:
@singledispatchmethod: for class methodsselfLimitations:
multipledispatch library (third-party)Use cases:
vs if/elif chains:
Registry inspection:
func.registry: dict of registered types and handlersfunc.register(type, func): register if you have handler functionForward references:
func.register('TypeName') in Python 3.10+