This issue tracker has been migrated to GitHub, and is currently read-only.
For more information, see the GitHub FAQs in the Python's Developer Guide.

classification
Title: functools.singledispatchmethod interacts poorly with subclasses
Type: behavior Stage:
Components: Library (Lib) Versions: Python 3.8
process
Status: open Resolution:
Dependencies: Superseder:
Assigned To: Nosy List: Tim Mitchell2, bojan.jovanovic.gtech, dschaumont, lukasz.langa, methane
Priority: normal Keywords:

Created on 2019-03-28 03:42 by Tim Mitchell2, last changed 2022-04-11 14:59 by admin.

Files
File name Uploaded Description Edit
methoddispatch36.py Tim Mitchell2, 2019-03-28 03:42 alternate implementation from methoddispatch package
singledispatchmethod.py Tim Mitchell2, 2019-04-12 04:43 improved implementation
singledispatchmethod.py Tim Mitchell2, 2022-03-18 06:05
test_sdm.py Tim Mitchell2, 2022-03-18 06:10 implementation tests
Messages (5)
msg339008 - (view) Author: Tim Mitchell (Tim Mitchell2) * Date: 2019-03-28 03:42
The new functools.singledispatchmethod (issue32380) class interacts poorly with subclasses.
There is no way for a sub-class to override or extend the dispatch registry.
E.g.

class BaseVistor:
   @singledispatchmethod
   def visit(self, obj):
      raise ValueError('Explict vistor implementation missing)

class AVisitor(BaseVisitor):
   # problem: here we can only register against base class method
   @BaseVistor.visit.reister(int)
   def visit_int(self, obj):
       print ('integer')

The AVistor class has now changed the dispatch registry for BaseVistor class which is bad.

To fix this the dispatch registry needs to be copied for each subclass and an alternate register mechanism provided for subclasses to register against a subclass method.
See attached file and pypi methoddispatch for details :)
msg340005 - (view) Author: Tim Mitchell (Tim Mitchell2) * Date: 2019-04-12 04:43
Attached is an improved implementation that does not use a module level register() function.  
It makes the code in the original post work as expected: The `@BaseVisitor.visit.register()` decorator on the `AVisitor` class does not modify the base class dispatch table.  This works by constructing the dispatch registry in the `__init_subclass__` method instead.
msg370758 - (view) Author: Dries Schaumont (dschaumont) Date: 2020-06-05 10:19
I am interested in the fix, added myself to nosy list.
msg371014 - (view) Author: Łukasz Langa (lukasz.langa) * (Python committer) Date: 2020-06-08 16:51
The proposed fix requires using a required base class which I'd like to avoid.
msg415470 - (view) Author: Tim Mitchell (Tim Mitchell2) * Date: 2022-03-18 06:05
I've come up with a version that does not require a base class.

Seems a bit hacky as the descriptor __get__ method now modifies the class to put the dispatch table in place the first time the method is accessed.
History
Date User Action Args
2022-04-11 14:59:13adminsetgithub: 80638
2022-03-18 06:10:24Tim Mitchell2setfiles: + test_sdm.py
2022-03-18 06:05:56Tim Mitchell2setfiles: + singledispatchmethod.py

messages: + msg415470
2020-10-27 17:27:48bojan.jovanovic.gtechsetnosy: + bojan.jovanovic.gtech
2020-06-08 16:51:53lukasz.langasetmessages: + msg371014
2020-06-05 10:19:07dschaumontsetnosy: + dschaumont
messages: + msg370758
2019-04-12 04:43:16Tim Mitchell2setfiles: + singledispatchmethod.py

messages: + msg340005
2019-03-28 04:28:55methanesetnosy: + lukasz.langa
2019-03-28 03:42:39Tim Mitchell2create