Support dynamic overload

in typing.py

NoType = object()

def cast_overload(func, overload_func, type=NoType):
    """If tpye is NoType, type = Type[overload_func]"""
    f = getattr(func, "__func__", func)
    of = getattr(overload_func, "__func__", overload_func)
    try:
        _overload_registry[f.__module__][f.__qualname__][
            of.__code__.co_firstlineno
        ] = overload_func
    except AttributeError:
        # Not a normal function; ignore.
        pass
    return overload_func

Usage

from typing import Callable, Concatenate, LiteralString, cast_overload

factory_dict = dict[str, Callable]()


def factory(key, *args, **kwargs):
    return factory_dict[key](*args, **kwargs)


def register[K: LiteralString](key: K):
    def decorator[**P, T](func: Callable[P, T]):
        factory_dict[key] = func
        return cast_overload(factory, func, Callable[Concatenate[K, P], T])

    return decorator


@register("function1")
def func1(x, y, z):
    pass


@register("function2")
def func2(a, b, c):
    pass

This can support type hint for Interface & implementation

There’s functools.singledispatch()

2 Likes

singledispatch fixes the first argument as the dispatch type, and dispatch by itself.

I want to dispatch by myself and the first argument of implementation is not type for dispatch.

What i want is more like overload for pre-defined function

You can dispatch by yourself using the .dispatch() API:

from functools import singledispatch

@singledispatch
def visit(x: object) -> None:
    print("visisted object")

@visit.register
def visit_int(x: int) -> None:
    print("visisted int")

@visit.register
def visit_str(x: str) -> None:
    print("visisted str")

str_visitor = visit.dispatch(str)
assert str_visitor is visit_str
str_visitor(object())
# visited str