mirror of
https://github.com/python/cpython.git
synced 2025-12-08 06:10:17 +00:00
gh-140873: Add support of non-descriptor callables in functools.singledispatchmethod() (GH-140884)
This commit is contained in:
parent
b99db92dde
commit
b2b68d40f8
5 changed files with 52 additions and 3 deletions
|
|
@ -672,7 +672,7 @@ The :mod:`functools` module defines the following functions:
|
||||||
dispatch>` :term:`generic function`.
|
dispatch>` :term:`generic function`.
|
||||||
|
|
||||||
To define a generic method, decorate it with the ``@singledispatchmethod``
|
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*
|
that the dispatch happens on the type of the first non-*self* or non-*cls*
|
||||||
argument::
|
argument::
|
||||||
|
|
||||||
|
|
@ -716,6 +716,9 @@ The :mod:`functools` module defines the following functions:
|
||||||
|
|
||||||
.. versionadded:: 3.8
|
.. versionadded:: 3.8
|
||||||
|
|
||||||
|
.. versionchanged:: next
|
||||||
|
Added support of non-:term:`descriptor` callables.
|
||||||
|
|
||||||
|
|
||||||
.. function:: update_wrapper(wrapper, wrapped, assigned=WRAPPER_ASSIGNMENTS, updated=WRAPPER_UPDATES)
|
.. function:: update_wrapper(wrapper, wrapped, assigned=WRAPPER_ASSIGNMENTS, updated=WRAPPER_UPDATES)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -498,6 +498,14 @@ difflib
|
||||||
(Contributed by Jiahao Li in :gh:`134580`.)
|
(Contributed by Jiahao Li in :gh:`134580`.)
|
||||||
|
|
||||||
|
|
||||||
|
functools
|
||||||
|
---------
|
||||||
|
|
||||||
|
* :func:`~functools.singledispatchmethod` now supports non-:term:`descriptor`
|
||||||
|
callables.
|
||||||
|
(Contributed by Serhiy Storchaka in :gh:`140873`.)
|
||||||
|
|
||||||
|
|
||||||
hashlib
|
hashlib
|
||||||
-------
|
-------
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1083,7 +1083,10 @@ def __call__(self, /, *args, **kwargs):
|
||||||
'singledispatchmethod method')
|
'singledispatchmethod method')
|
||||||
raise TypeError(f'{funcname} requires at least '
|
raise TypeError(f'{funcname} requires at least '
|
||||||
'1 positional argument')
|
'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):
|
def __getattr__(self, name):
|
||||||
# Resolve these attributes lazily to speed up creation of
|
# Resolve these attributes lazily to speed up creation of
|
||||||
|
|
|
||||||
|
|
@ -2785,7 +2785,7 @@ class Slot:
|
||||||
@functools.singledispatchmethod
|
@functools.singledispatchmethod
|
||||||
@classmethod
|
@classmethod
|
||||||
def go(cls, item, arg):
|
def go(cls, item, arg):
|
||||||
pass
|
return item - arg
|
||||||
|
|
||||||
@go.register
|
@go.register
|
||||||
@classmethod
|
@classmethod
|
||||||
|
|
@ -2794,7 +2794,9 @@ def _(cls, item: int, arg):
|
||||||
|
|
||||||
s = Slot()
|
s = Slot()
|
||||||
self.assertEqual(s.go(1, 1), 2)
|
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, 1), 2)
|
||||||
|
self.assertEqual(Slot.go(1.5, 1), 0.5)
|
||||||
|
|
||||||
def test_staticmethod_slotted_class(self):
|
def test_staticmethod_slotted_class(self):
|
||||||
class A:
|
class A:
|
||||||
|
|
@ -3485,6 +3487,37 @@ def _(item, arg: bytes) -> str:
|
||||||
self.assertEqual(str(Signature.from_callable(A.static_func)),
|
self.assertEqual(str(Signature.from_callable(A.static_func)),
|
||||||
'(item, arg: int) -> str')
|
'(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:
|
class CachedCostItem:
|
||||||
_cost = 1
|
_cost = 1
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,2 @@
|
||||||
|
Add support of non-:term:`descriptor` callables in
|
||||||
|
:func:`functools.singledispatchmethod`.
|
||||||
Loading…
Add table
Add a link
Reference in a new issue