Package: dispatchlib
DispatchlibDispatchlib is a metaprogramming library for creating single-dispatched generic functions, similar tofunctools.singledispatch, with a few additional goodies:Supports type annotations that utilize Python's builtintypingmodule.Lazy-loads string annotations (i.e. types declared via string).Priority dispatching: you can set the "priority" of an overloaded implementation. Basicallydispatchlib.dispatchis a big olif elif eliffactory, and the order is determined by@f.register(priority=?)A "metadispatch" that lets you overload the dispatcher itself. (Hard to explain; see example for clarification.)Dispatchlib'sdispatchdecorator is not a strict superset offunctools.singledispatch. There are a few things infunctools.singledispatchthat are not insingle:dispatchlib.dispatchrequires that you always call the register decorator like this:@f.regsiter()whereasfunctools.singledispatch. The reason why is becausedispatchlib.dispatchcan dispatch not just based on types but also based on functions , so the first arg in theregisterdecorator being a function is not sufficient to conclude whether it's being called or not prior to decoration.functools.singledispatchsupports dynamic polymorphism using__mro__, whereasdispatchlib.dispatchdispatches based on running a check for each overloaded implementation; by default, checks are run in FIFO order, with the exception of the "base" function, which is always run last.functools.singledispatchis faster.InstallpipinstalldispatchlibExamplesBasic Example 1fromdispatchlibimportdispatchfromtypingimportAny,Dict,List@dispatchdefmul_by_two(x:Any):"""Multiply numbers by two"""returnx*2# Support for builtin typing module:@mul_by_two.register()def_(x:Dict[Any,int]):return{k:v*2fork,vinx.items()}@mul_by_two.register()def_(x:List[int]):return[i*2foriinx]# lazy-loaded type hints:@mul_by_two.register()def_(x:'pandas.DataFrame'):returnx.select_dtypes(include='number')*2# Assert it all works as intended:assertmul_by_two(3)==6assertmul_by_two([2,3,4])==[4,6,8]assertmul_by_two({'a':2,'b':3})=={'a':4,'b':6}# Testing lazy-load functionality:try:importpandasaspdexceptModuleNotFoundError:passelse:print(mul_by_two(pd.DataFrame({'a':range(10),'b':['exclude me']*10})))Basic Example 2fromdispatchlibimportDispatcherfromtypesimportFunctionType# You can call Dispatcher() to skip a implementation# It's also useful for type-checking.always_return_figure=Dispatcher()assertisinstance(always_return_figure,Dispatcher)assertisinstance(always_return_figure,FunctionType)importmatplotlibimportmatplotlib.pyplotasplt# Implementations can be chained together:@always_return_figure.register('matplotlib.pyplot.Axes')@always_return_figure.register('matplotlib.pyplot.Subplot')defreturn_figure1(x):returnx.figure@always_return_figure.register('matplotlib.pyplot.Figure')defreturn_figure2(x):returnxfig,ax=plt.subplots()assertalways_return_figure(ax)==always_return_figure(fig)plt.close(fig)Metadispatch examplefromdispatchlibimportdispatchfromdispatchlibimportmetadispatchclassHTTPException(Exception):status_code:intclassPageNotFoundError(HTTPException):status_code:int=404classForbiddenError(HTTPException):status_code:int=403custom_metadispatcher=metadispatch()# This metadispatcher knows how to interpret when a user registers a function# with an integer: The integer represents an HTTP status code.@custom_metadispatcher.register(lambdaval:isinstance(val,int))def_(val:int):defchecker(x:HTTPException):returnx.status_code==valreturnchecker@dispatch(metadispatcher=custom_metadispatcher)defstatus_code_message(code):raiseTypeError('Unknown status code.')@status_code_message.register(404)def_(code):return'Page not found.'@status_code_message.register(403)def_(code):return'Forbidden.'assertstatus_code_message(PageNotFoundError())=='Page not found.'assertstatus_code_message(ForbiddenError())=='Forbidden.'WarningI'm currently using Dispatchlib as part of another larger project. Dispatchlib exists separately of that project because I think it makes sense as its own separate thing. With that said, I plan on doing some bugfixing of use-cases as that project unfolds. So for this version of dispatchlib:There may be some bugs.The API may break between changes.When this message is no longer here, consider the module more stable.I'm interested toTodocreatedispatchmethodakin to singledispatchmethod.decorator for making functions and methods dispatchable without immediately registering them to a dispatcher.support MRO for dispatching somehow.make code faster.make code more DRY via abstracting out the shared stuff in bothmetadispatchanddispatch.flesh out docs.add unit-tests.