{"id":9938,"library":"methoddispatch","title":"Method Dispatch","description":"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.","status":"active","version":"5.0.1","language":"en","source_language":"en","source_url":"https://github.com/seequent/methoddispatch","tags":["dispatch","singledispatch","decorator","methods","polymorphism"],"install":[{"cmd":"pip install methoddispatch","lang":"bash","label":"Install stable version"}],"dependencies":[],"imports":[{"note":"While similar in concept, `methoddispatch` is distinct from `functools.singledispatch` as it targets class methods. Using `functools.singledispatch` directly on a class method will not provide the intended behavior.","wrong":"from functools import singledispatch","symbol":"methoddispatch","correct":"from methoddispatch import methoddispatch"}],"quickstart":{"code":"from methoddispatch import methoddispatch\n\nclass MyClass:\n    @methoddispatch\n    def process(self, arg):\n        return f\"Processing generic {type(arg).__name__}: {arg}\"\n\n    @process.register(int)\n    def _(self, arg: int):\n        return f\"Processing int: {arg * 2}\"\n\n    @process.register(str)\n    def _(self, arg: str):\n        return f\"Processing str: {arg.upper()}\"\n\n    @process.register(list) # Will match list[int] as per v5.0.0 behavior\n    def _(self, arg: list):\n        return f\"Processing list of length: {len(arg)}\"\n\n# Example usage\ninstance = MyClass()\nprint(instance.process(10))\nprint(instance.process(\"hello\"))\nprint(instance.process([1, 2, 3]))\nprint(instance.process(3.14))\nprint(instance.process([4, 5])) # Demonstrates list[int] matching list handler","lang":"python","description":"This quickstart demonstrates how to define a class method with the `@methoddispatch` decorator and register different implementations for specific argument types. The generic `process` method serves as the fallback, while `int`, `str`, and `list` types have specialized implementations."},"warnings":[{"fix":"Refactor any plain functions using `methoddispatch` into class methods, or switch to `functools.singledispatch` for non-method functions.","message":"Version 3.0 dropped support for decorating plain functions. `methoddispatch` must now be applied to methods within a class.","severity":"breaking","affected_versions":"<3.0 to 3.0+"},{"fix":"Update your registration calls from `register(MyClass.method, type)` to `MyClass.method.register(type)`.","message":"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()`).","severity":"breaking","affected_versions":"<3.0 to 3.0+"},{"fix":"Be aware that generic type hints are treated as their base type for dispatch. If you need to differentiate between, say, `list[int]` and `list[str]`, you'll need to implement additional runtime checks within your `list` handler.","message":"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.","severity":"gotcha","affected_versions":"5.0.0+"}],"env_vars":null,"last_verified":"2026-04-17T00:00:00.000Z","next_check":"2026-07-16T00:00:00.000Z","problems":[{"fix":"Ensure `@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`).","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.","error":"TypeError: The first argument to register must be a class."},{"fix":"Confirm 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`.","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.","error":"AttributeError: 'function' object has no attribute 'register'"},{"fix":"Register 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]`.","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`).","error":"Unexpected dispatch to base type handler for generic types like list[int]"}]}