Let’s talk about Python 3's fantastic single-dispatch generic function.

When all you have is a hammer.
Photo by DevVrat Jadon / Unsplash


What’s a single-dispatch generic function?

It’s when you do this:

import json

from datetime import datetime
from decimal import Decimal
from functools import singledispatch

def serialize(obj):
    """Raise error for attempts to serialize unimplemented types."""
    raise TypeError

def _(obj: datetime):
    """Serialize datetimes to ISO format."""
    return obj.isoformat()

def _(obj: Decimal):
    """Serialize decimals to string."""
    return f"Decimal({str(obj)})"

json.dumps(obj, default=serialize)

Instead of doing this:

import json

from datetime import datetime
from decimal import Decimal

def serialize(obj):
    """Serialize objects that the json library can't handle by default."""
    if isinstance(obj, datetime):
        result = obj.isoformat()
    elif isinstance(obj, Decimal):
        result = f"Decimal({str(obj)})"
        raise TypeError
    return result

json.dumps(obj, default=serialize)

Why use @singledispatch?

Because it enables easier unit-testing and typed code. (That's right, those type hints aren't just hints anymore!) Also, code reuse is simple -- just stack decorators:

def _(obj):
    # Implement numeric-specific function here

There's nothing stopping you from using the traditional stack of if-elif-else statements if you prefer, but this is a nice alternative that's great to have on hand.


The concept has been around Python for years. It was proposed in PEP 443 in 2013 and then implemented in Python 3.4 a year later. It essentially boils down to two parts:

  • A generic function. This is a function composed of several smaller functions that each implement the same operation for a different set of input types. When a generic function is called, the implementation that gets used is determined by the dispatch algorithm.
  • Single dispatch. This just means that the implementation is chosen by inspecting the type of only one of the inputs.

Polymorphism at its finest.