Method Resolution

Multiple dispatch selects the function from the types of the inputs.

@dispatch(int)deff(x):# increment integersreturnx+1@dispatch(float)deff(x):# decrement floatsreturnx-1
>>>f(1)# 1 is an int, so increment2>>>f(1.0)# 1.0 is a float, so decrement0.0

Union Types

Similarly to the builtinisinstance operation you specify multiple validtypes with a tuple.

@dispatch((list,tuple))deff(x):""" Apply ``f`` to each element in a list or tuple """return[f(y)foryinx]
>>>f([1,2,3])[2, 3, 4]>>>f((1,2,3))[2, 3, 4]

Abstract Types

You can also use abstract classes likeIterable andNumber inplace of union types like(list,tuple) or(int,float).

fromcollectionsimportIterable# @dispatch((list, tuple))@dispatch(Iterable)deff(x):""" Apply ``f`` to each element in an Iterable """return[f(y)foryinx]

Selecting Specific Implementations

If multiple valid implementations exist then we use the most specificone. In the following example we build a function to flatten nestediterables.

@dispatch(Iterable)defflatten(L):returnsum([flatten(x)forxinL],[])@dispatch(object)defflatten(x):return[x]
>>>flatten([1,2,3])[1, 2, 3]>>>flatten([1,[2],3])[1, 2, 3]>>>flatten([1,2,(3,4),[[5]],[(6,7),(8,9)]])[1, 2, 3, 4, 5, 6, 7, 8, 9]

Because strings are iterable they too will be flattened

>>>flatten([1,'hello',3])[1, 'h', 'e', 'l', 'l', 'o', 3]

We avoid this by specializingflatten tostr. Becausestr ismore specific thanIterable this function takes precedence forstrings.

@dispatch(str)defflatten(s):returns
>>>flatten([1,'hello',3])[1, 'hello', 3]

Themultipledispatch project depends on Python’sissubclassmechanism to determine which types are more specific than others.

Multiple Inputs

All of these rules apply when we introduce multiple inputs.

@dispatch(object,object)deff(x,y):returnx+y@dispatch(object,float)deff(x,y):""" Square the right hand side if it is a float """returnx+y**2
>>>f(1,10)11>>>f(1.0,10.0)101.0

Ambiguities

However ambiguities arise when different implementations of a functionare equally valid

@dispatch(float,object)deff(x,y):""" Square left hand side if it is a float """returnx**2+y
>>>f(2.0,10.0)?

Which result do we expect,2.0**2+10.0 or2.0+10.0**2? Thetypes of the inputs satisfy three different implementations, two ofwhich have equal validity

input types:    float, floatOption 1:       object, objectOption 2:       object, floatOption 3:       float, object

Option 1 is strictly less specific than either options 2 or 3 so wediscard it. Options 2 and 3 however are equally specific and so it isunclear which to use.

To resolve issues like thismultipledispatch inspects the typesignatures given to it and searches for ambiguities. It then raises awarning like the following:

multipledispatch/dispatcher.py:74: AmbiguityWarning:Ambiguities exist in dispatched function fThe following signatures may result in ambiguous behavior:    [object, float], [float, object]Consider making the following additions:@dispatch(float, float)def f(...)

This warning occurs when you write the function and guides you to createan implementation to break the ambiguity. In this case, a function withsignature(float,float) is more specific than either options 2 or 3and so resolves the issue. To avoid this warning you should implementthis new functionbefore the others.

@dispatch(float,float)deff(x,y):...@dispatch(float,object)deff(x,y):...@dispatch(object,float)deff(x,y):...

If you do not resolve ambiguities by creating more specific functionsthen one of the competing functions will be selected pseudo-randomly.