{
  "$type": "site.standard.document",
  "canonicalUrl": "https://rednafi.com/python/singledispatch/",
  "description": "Replace complex if-elif chains with functools.singledispatch for type-based function dispatch and cleaner polymorphic behavior in Python.",
  "path": "/python/singledispatch/",
  "publishedAt": "2020-04-05T00:00:00.000Z",
  "site": "at://did:plc:fgtm2c26vfcj74rfmeggbyqj/site.standard.publication/3mnl6f7ob462z",
  "tags": [
    "Python"
  ],
  "textContent": "_Updated on 2022-02-13_: _Change import style of functools.singledispatch._\n\nRecently, I was refactoring a portion of a Python function that somewhat looked like this:\n\nThis pattern gets tedious when the number of conditions and actionable functions start to\ngrow. I was looking for a functional approach to avoid defining and calling three different\nfunctions that do very similar things. Situations like this is where [parametric\npolymorphism] comes into play. The idea is, you have to define a single function that'll be\ndynamically overloaded with alternative implementations based on the type of the function\narguments.\n\nFunction overloading & generic functions\n\nFunction overloading is a specific type of polymorphism where multiple functions can\nhave the same name with different implementations. Calling an overloaded function will run a\nspecific implementation of that function based on some prior conditions or appropriate\ncontext of the call.\n\nWhen function overloading happens based on its argument types, the resulting function is\nknown as generic function. Let's see how Python's singledispatch decorator can help to\ndesign generic functions and refactor the icky code above.\n\nSingledispatch\n\nPython fairly recently added partial support for function overloading in _Python 3.4_. They\ndid this by adding a neat little decorator to the _functools_ module called\nsingledispatch. In _Python 3.8_, there is another decorator for methods called\nsingledispatchmethod. This decorator will transform your regular function into a single\ndispatch generic function.\n\n> A generic function is composed of multiple functions implementing the same operation for\n> different types. Which implementation should be used during a call is determined by the\n> dispatch algorithm. When the implementation is chosen based on the type of a single\n> argument, this is known as single dispatch.\n\nAs [PEP-443] said, singledispatch only happens based on the first argument's type. Let's\ntake a look at an example to see how this works!\n\nExample-1: Singledispatch with built-in argument type\n\nLet's consider the following code:\n\nRunning this code will return:\n\nThe above code snippet applies process_int or process_float functions on the incoming\nnumber based on its type. Now let's see how the same thing can be achieved with\nsingledispatch:\n\nRunning this will return the same result as before.\n\nExample-2: Singledispatch with custom argument type\n\nSuppose, you want to dispatch your function based on custom argument type where the type\nwill be deduced from data. Consider this example:\n\nRunning this snippet will print out:\n\nTo refactor this with singledispatch, you can create two data types Cat and Dog. When\nyou make Cat and Dog objects from the classes and pass them through the process\nfunction, singledispatch will take care of dispatching the appropriate implementation of\nthat function.\n\nRunning this will print out the same output as before:\n\nFurther reading\n\n- [Transform a function into a single dispatch generic function]\n- [Function overloading]\n\n\n\n\n[parametric polymorphism]:\n    https://en.wikipedia.org/wiki/Parametric_polymorphism\n\n[pep-443]:\n    https://peps.python.org/pep-0443/\n\n[transform a function into a single dispatch generic function]:\n    https://docs.python.org/3/library/functools.html#functools.singledispatch\n\n[function overloading]:\n    https://en.wikipedia.org/wiki/Function_overloading",
  "title": "Generic functions with Python's singledispatch"
}