Method Dispatch
methoddispatch provides a decorator similar to `functools.singledispatch` but specifically designed for dispatching class methods based on the type of their arguments. It extends Python's built-in single dispatch functionality to work seamlessly within classes, supporting different implementations for various argument types. The current version is 5.0.1, with an irregular release cadence driven by feature enhancements and Python version compatibility.
Common errors
-
TypeError: The first argument to register must be a class.
cause Attempting to register a type for a `@methoddispatch` decorated function that is not part of a class, or trying to register a non-class object.fixEnsure `@methoddispatch` is applied to a method within a class, and that all types passed to `.register()` are actual class types (e.g., `int`, `str`, `MyCustomClass`). -
AttributeError: 'function' object has no attribute 'register'
cause This typically occurs when trying to access `.register` on a function that was not decorated with `@methoddispatch` or when using an old module-level `register` approach after v3.0.fixConfirm the function is decorated with `@methoddispatch`. If it is a method, access `register` via `ClassName.method_name.register(Type)`. If it's a plain function, use `functools.singledispatch`. -
Unexpected dispatch to base type handler for generic types like list[int]
cause You registered a handler for a generic type like `list[int]` (or expected it to be distinct), but `methoddispatch` v5.0.0+ dispatches only on the base type (`list`).fixRegister for the base type (e.g., `list`) and implement logic inside that handler to further differentiate based on generic arguments if needed. For example, `isinstance(arg, list)` will match `list[int]`.
Warnings
- breaking Version 3.0 dropped support for decorating plain functions. `methoddispatch` must now be applied to methods within a class.
- breaking Starting from version 3.0, the module-level `register` function was deprecated in favor of accessing the `register` method directly from the decorated method (e.g., `MyClass.method.register()`).
- gotcha As of v5.0.0, while simple type annotations like `list[int]` are supported, dispatching only occurs on the base type (e.g., `list`). This means `list[int]` will match a handler registered for `list`, not `list[int]` specifically.
Install
-
pip install methoddispatch
Imports
- methoddispatch
from functools import singledispatch
from methoddispatch import methoddispatch
Quickstart
from methoddispatch import methoddispatch
class MyClass:
@methoddispatch
def process(self, arg):
return f"Processing generic {type(arg).__name__}: {arg}"
@process.register(int)
def _(self, arg: int):
return f"Processing int: {arg * 2}"
@process.register(str)
def _(self, arg: str):
return f"Processing str: {arg.upper()}"
@process.register(list) # Will match list[int] as per v5.0.0 behavior
def _(self, arg: list):
return f"Processing list of length: {len(arg)}"
# Example usage
instance = MyClass()
print(instance.process(10))
print(instance.process("hello"))
print(instance.process([1, 2, 3]))
print(instance.process(3.14))
print(instance.process([4, 5])) # Demonstrates list[int] matching list handler