-
Notifications
You must be signed in to change notification settings - Fork 74
Description
Dear multipledispatch developers,
I have done some customization to multipledispatch to fit the need of one of my libraries.
While some of the changes are very specific to my needs, I think that most of the changes might be interesting to commit upstream.
The patched version of @dispatch decorator is available at this link, as well as some unit tests.
I would like to have your suggestions on which (if any) of my changes you would deem interesting upstream. I try to summarize them here:
- new features:
-
do not store Dispatchers in a dict, but rather in a module. Note that this BREAKS backward compatibility. The motivation for doing this are strongly related to my specific needs (there is some summary in the multiline comment at line 366, but nonetheless I think that it might be a more natural way to store Dispatchers and being able to import them. There are a few tests on this: lines 366, 394.
-
allow @dispatch to be applied to classes. Tests at line 500, 647. This feature depends on the backward incompatible change concerning Dispatcher storage inside a module (rather than a dict).
-
allow dispatched functions to be replaced through @dispatch kwargs replaces=... and replaces_if=... . Implementation from line 79. Test at line 459, 669, 715. This feature depends on the backward incompatible change concerning Dispatcher storage inside a module (rather than a dict).
-
implementation of dispatching based on subtypes for dict, lists, tuple etc. This is already discussed in issue Dispatching to list subtypes #72, and there is also a WIP pull request WIP: Experiment to use pytypes to add support for python type hints #69. My implementation is very different from the two aforementioned approaches, and relies on custom defined classes named list_of(TYPES), tuple_of(TYPES), set_of(TYPES), dict_of(TYPES_FROM, TYPES_TO), where TYPES could be a tuple of types. I had laid out this part before learning about pytypes, so I am open to suggestions on replacing my custom made classes with pytypes. However, I personally do not like the square brackets in their notations: when declaring a @dispatch to take either int or floats one would use @dispatch((int, float)), where "OR" is denoted by a parenthesis, while for pytypes object on would need to write @dispatch(Tuple[int, float]), where "OR" is denoted by a square bracket. The notation of my implementation is instead list_of((int, float)). More implementation detail:
- the definition of custom *_of classes goes from line 428 to line 522
- I have a strong assumption in my code that, whenever I dispatch on iterable, I will always know the subtype. For this reason, I have disabled the plain iterables in a validation stage at line 524. This assumption might be too strong for general purposes, and is definitely NOT backward compatible.
- when calling the Dispatcher iterable input arguments are converted to the corresponding *_of types in the auxiliary function at line 553. In a similar way tuple expansion has been patched at line 599
- the implementation of conflict operators for *_of classes is custom made from line 635 to line 729
There are a few tests on this part:
- adaptation of upstream tests at lines 128, 144, 158
- custom conflict operators for *_of classes are tested at lines 224, 286, 342
- validation that standard iterable types have been disabled is on the test at line 552
- additional few tests related to class initialization at lines 564, 572, 596
- tests that subtypes provided to *_of properly account for inheritance at lines 731, 754, 776, 798, 822, 845, 866, 888, 910, 934
- one additional minor test at line 953
-
have MethodDispatcher account for inheritance. In the current master version, dispatched methods are not inherited. The work from line 192 to line 307 allows dispatched class methods to be inherited and possibly overridden. Tests for this are at line 967, 993, 1002, 1040.
-
allow lambda functions to be passed instead of hardcoded types. The typical use case for which I needed this was in the definition of arithmetic operators, e.g.
class F(object): def __init__(self, arg): self.arg = arg @dispatch(F) def __mul__(self, other): return self.arg*other.argPython interpreter fails on @dispatch(F) because F is not fully defined yet. My proposed solution has thus been to use
class F(object): def __init__(self, arg): self.arg = arg @dispatch(lambda cls: cls) def __mul__(self, other): return self.arg*other.argNote that in this case the evaluation of the signature is delayed to the first time the dispatched method is called.
Tests for this feature are: -
compatibility with optional default None argument. Implementation at line 732, test at line 1193
-
- minor changes:
- slightly changed the implementation for what concerns annotations. There are a few tests on this:
- new overload decorator, which can be called as
@overload''' rather than@overload()'' if the signature is provided through annotations. Implementation at line 419, test at line 1169. This is essentially a duplicate of @dispatch, so I might be willing to rename it back to dispatch before pushing upstream. - additional minor tests related to calling method from class rather than instance at line
- minor changes that break backward compatibility, and thus may not be worthy to push upstream:
Apologies for the long post, necessary to clearly present all features of the patched version of the library in order to understand from you which features might be of general interest.
ping @mrocklin @hameerabbasi @llllllllll @mariusvniekerk @shoyer who were involved in the aformentioned issues and pull requests.