8000 gh-85160: improve performance of singledispatchmethod by eendebakpt · Pull Request #107148 · python/cpython · GitHub
[go: up one dir, main page]

Skip to content

gh-85160: improve performance of singledispatchmethod #107148

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 32 commits into from
Aug 6, 2023
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
04fe64e
bpo-40988: Optimized singledispatchmethod access.
mental32 Nov 10, 2020
fc72bea
Merge branch 'main' into bpo-40988
AlexWaygood Jul 5, 2023
31d292b
Merge branch 'main' into singledispatchmethod3
eendebakpt Jul 23, 2023
5ae8348
add test for slotted classes
eendebakpt Jul 5, 2023
1edc0e3
add test for slotted classes
eendebakpt Jul 23, 2023
9a1ffae
update new entry with attribution to original author
eendebakpt Jul 23, 2023
3588943
add test for assignment to dispatched methods
eendebakpt Jul 23, 2023
af233d4
typo
eendebakpt Jul 23, 2023
d5aebdf
Update Lib/test/test_functools.py
eendebakpt Jul 23, 2023
b773f82
apply review suggestion
eendebakpt Jul 23, 2023
25e1915
Merge branch 'main' into singledispatchmethod3
eendebakpt Jul 23, 2023
593c923
Update Lib/functools.py
eendebakpt Jul 23, 2023
39bec6d
Update Lib/functools.py
eendebakpt Jul 23, 2023
d954244
use hasattr to check for slotted types
eendebakpt Jul 24, 2023
df2eeb5
make attrname private
eendebakpt Jul 24, 2023
774ec3c
review comments
eendebakpt Jul 24, 2023
f03ebba
use weakref for caching
eendebakpt Jul 30, 2023
b459718
Merge branch 'singledispatchmethod3' of githubeendebakpt:eendebakpt/c…
eendebakpt Jul 30, 2023
a422989
Merge branch 'main' into singledispatchmethod3
eendebakpt Jul 30, 2023
450ea12
make patchcheck
eendebakpt Jul 31, 2023
032ab24
review comments
eendebakpt Jul 31, 2023
18d7e43
Apply suggestions from code review
eendebakpt Jul 31, 2023
755efdd
Merge branch 'main' into singledispatchmethod3
eendebakpt Jul 31, 2023
56d342c
Ensure we only weakref() `obj` once
AlexWaygood Jul 31, 2023
a119e21
Get rid of the cache local variable
AlexWaygood Jul 31, 2023
47c18a5
Don't assign `caching` in the fast path
AlexWaygood Jul 31, 2023
2031680
Merge pull request #5 from AlexWaygood/even-more-singledispatchmethod…
eendebakpt Jul 31, 2023
ca691e8
remove check on obj being None
eendebakpt Jul 31, 2023
e8eeedd
eliminate caching variable
eendebakpt Jul 31, 2023
307f0c1
Merge pull request #6 from eendebakpt/singledispatchmethod3b
eendebakpt Aug 1, 2023
afea7b9
Test slotted staticmethods on instances as well as the class
AlexWaygood Aug 1, 2023
b43dcee
eliminate method variable and reduce attribute lookups
eendebakpt Aug 1, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
use weakref for caching
  • Loading branch information
eendebakpt committed Jul 30, 2023
commit f03ebba2dec387f63019915dead4e1c7f367797e
18 changes: 12 additions & 6 deletions Lib/functools.py
Original file line number Diff line number Diff line change
Expand Up @@ -928,23 +928,27 @@ class singledispatchmethod:
"""

def __init__(self, func):
import weakref # lazy import
if not callable(func) and not hasattr(func, "__get__"):
raise TypeError(f"{func!r} is not callable or a descriptor")

self.dispatcher = singledispatch(func)
self.func = func
self._method_cache = weakref.WeakKeyDictionary()
self._all_weakrefable_instances = True

def register(self, cls, method=None):
"""generic_method.register(cls, func) -> func

Registers a new implementation for the given *cls* on a *generic_method*.
"""
self._method_cache.clear()
return self.dispatcher.register(cls, func=method)

def __set_name__(self, owner, name):
self._attrname = name

def __get__(self, obj, cls=None):
if self._all_weakrefable_instances and cls is not None and obj in self._method_cache:
return self._method_cache[obj]

def _method(*args, **kwargs):
method = self.dispatcher.dispatch(args[0].__class__)
return method.__get__(obj, cls)(*args, **kwargs)
Expand All @@ -953,9 +957,11 @@ def _method(*args, **kwargs):
_method.register = self.register
update_wrapper(_method, self.func)

# not all objects have __dict__ (e.g. classes with __slots__)
if hasattr(obj, '__dict__'):
obj.__dict__[self._attrname] = _method
if self._all_weakrefable_instances and cls is not None:
try:
self._method_cache[obj] = _method
except TypeError:
self._all_weakrefable_instances = False

return _method

Expand Down
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
Improve performance of :class:`functools.singledispatchmethod` by caching the generated dispatch wrapper.
Optimization suggested by frederico. Patch by @mental32 and @eendebakpt.
Optimization suggested by frederico. Patch by @mental32, @alexwaygood and @eendebakpt.
0