gh-85294: Handle missing arguments to @singledispatchmethod gracefully by ammaraskar · Pull Request #21471 · python/cpython

I measure a small, but significant, speedup for the following patch (relative to your PR branch) when @singledispatchmethod is used on slotted classes. Note that funcname is only calculated in the except IndexError block:

--- a/Lib/functools.py
+++ b/Lib/functools.py
@@ -967,12 +967,14 @@ def __get__(self, obj, cls=None):
                 return _method
 
         dispatch = self.dispatcher.dispatch
-        funcname = getattr(self.func, '__name__', 'singledispatchmethod method')
         def _method(*args, **kwargs):
-            if not args:
+            try:
+                key = args[0].__class__
+            except IndexError:
+                funcname = getattr(self.func, '__name__', 'singledispatchmethod method')
                 raise TypeError(f'{funcname} requires at least '
-                                '1 positional argument')
-            return dispatch(args[0].__class__).__get__(obj, cls)(*args, **kwargs)
+                                '1 positional argument') from None
+            return dispatch(key).__get__(obj, cls)(*args, **kwargs)

Benchmark script:

import pyperf

runner = pyperf.Runner()
runner.timeit(name="bench singledispatchmethod",
              stmt="""
_ = t.go(1, 1)
""",
setup="""
from functools import singledispatch, singledispatchmethod

class Test:
    __slots__ = ()

    @singledispatchmethod
    def go(self, item, arg):
        pass

    @go.register
    def _(self, item: int, arg):
        return item + arg

t = Test()
""")

I could not measure any performance difference from my original suggestion at #21471 (comment).

Numbers from that benchmark:

  • With this PR currently:
    bench singledispatchmethod: Mean +- std dev: 824 ns +- 8 ns
    
  • With my proposed patch added to this PR:
    bench singledispatchmethod: Mean +- std dev: 810 ns +- 20 ns
    

I'm fine with it if you want to defer optimising this area of code for now; I agree there are lots of open bug reports regarding @singledispatchmethod, and that those should take priority.