HiveBrain v1.2.0
Get Started
← Back to all entries
patternpythonMinorCanonical

Multiple dispatch decorator classes in Python

Submitted by: @import:stackexchange-codereview··
0
Viewed 0 times
dispatchpythonclassesmultipledecorator

Problem

This is based on my first review and the suggested points in "Multiple dispatch decorator in Python":

```
import inspect
from functools import wraps, update_wrapper, partial

class multi_dispatch(object):

"""
Returns a multiple dispatch version of the function, that has a "register"
method with which new versions of the function can be registered. These
functions each must have annotated parameters with the types they shall be
called with. Keyword parameters and "self" must not be annotated.

The decorated function works by searching for an exact match for the types
of the given arguments. If no match is found, the function on which this
decorator has been used, is called. If you don't want this, raise a
TypeError inside the function.

>>> FMT = 'In {} the {} and {} collide.'
>>> FMT_SA = 'In {} the {} is smashed to bits by {}.'
>>> FMT_AS = 'In {} the {} is hit by the {}.'
>>>
>>> class GameObject(object):
... def __init__(self, name):
... self.name = name
...
... def __repr__(self):
... return self.name
...
...
>>> class Asteroid(GameObject):
... pass
...
...
>>> class Spaceship(GameObject):
... pass
...
...
>>> class Starcluster(GameObject):
... @multi_dispatch
... def collide(self, a, b):
... print(FMT.format(self, a, b))
...
... @collide.register
... def collide(self, a: Spaceship, b: Asteroid):
... print(FMT_SA.format(self, a, b))
...
... @collide.register
... def collide(self, a: Asteroid, b: Spaceship):
... print(FMT_AS.format(self, a, b))
...
...
>>> a = Asteroid('Iris')
>>> s = Spaceship('Voyager')
>>> sc = Starcluster('Messier 69')
>>>
>>> sc.collide(a, s)
In Messier 69 the Iris is hit by the Voyager.
>>> sc.collide(s, 'a grain of dust')
In Messier 69 the Voyager and a grain

Solution

The code itself looks quite pretty and overall readable, considering that the topic itself requires some knowledge about the Python language internals. Some suggestions in descending order of urgency:

-
You should either document that @classmethod and @staticmethod are not supported, or implement support for them.

-
It might be sensible to add a sanity-check in case someone annotates a keyword argument.

-
I prefer to use formats instead of string concatenation, even for exception messages:

raise TypeError("duplicate registration of: {}".format(
                    annotation))


This allows for easier extension of the error message (in case it turns out to be too shallow at some point; one might want to include the overloaded functions name at some point in the future) and makes it easier to read.

Explicitly inheriting from object is not required anymore in Python 3, but it is not wrong to explicitly specify that.

Code Snippets

raise TypeError("duplicate registration of: {}".format(
                    annotation))

Context

StackExchange Code Review Q#57019, answer score: 3

Revisions (0)

No revisions yet.