dispatch>` :term:`generic function`.
To define a generic method, decorate it with the ``@singledispatchmethod``
- decorator. When defining a function using ``@singledispatchmethod``, note
+ decorator. When defining a method using ``@singledispatchmethod``, note
that the dispatch happens on the type of the first non-*self* or non-*cls*
argument::
.. versionadded:: 3.8
+ .. versionchanged:: next
+ Added support of non-:term:`descriptor` callables.
+
.. function:: update_wrapper(wrapper, wrapped, assigned=WRAPPER_ASSIGNMENTS, updated=WRAPPER_UPDATES)
'singledispatchmethod method')
raise TypeError(f'{funcname} requires at least '
'1 positional argument')
- return self._dispatch(args[0].__class__).__get__(self._obj, self._cls)(*args, **kwargs)
+ method = self._dispatch(args[0].__class__)
+ if hasattr(method, "__get__"):
+ method = method.__get__(self._obj, self._cls)
+ return method(*args, **kwargs)
def __getattr__(self, name):
# Resolve these attributes lazily to speed up creation of
@functools.singledispatchmethod
@classmethod
def go(cls, item, arg):
- pass
+ return item - arg
@go.register
@classmethod
s = Slot()
self.assertEqual(s.go(1, 1), 2)
+ self.assertEqual(s.go(1.5, 1), 0.5)
self.assertEqual(Slot.go(1, 1), 2)
+ self.assertEqual(Slot.go(1.5, 1), 0.5)
def test_staticmethod_slotted_class(self):
class A:
self.assertEqual(str(Signature.from_callable(A.static_func)),
'(item, arg: int) -> str')
+ def test_method_non_descriptor(self):
+ class Callable:
+ def __init__(self, value):
+ self.value = value
+ def __call__(self, arg):
+ return self.value, arg
+
+ class A:
+ t = functools.singledispatchmethod(Callable('general'))
+ t.register(int, Callable('special'))
+
+ @functools.singledispatchmethod
+ def u(self, arg):
+ return 'general', arg
+ u.register(int, Callable('special'))
+
+ v = functools.singledispatchmethod(Callable('general'))
+ @v.register(int)
+ def _(self, arg):
+ return 'special', arg
+
+ a = A()
+ self.assertEqual(a.t(0), ('special', 0))
+ self.assertEqual(a.t(2.5), ('general', 2.5))
+ self.assertEqual(A.t(0), ('special', 0))
+ self.assertEqual(A.t(2.5), ('general', 2.5))
+ self.assertEqual(a.u(0), ('special', 0))
+ self.assertEqual(a.u(2.5), ('general', 2.5))
+ self.assertEqual(a.v(0), ('special', 0))
+ self.assertEqual(a.v(2.5), ('general', 2.5))
+
class CachedCostItem:
_cost = 1