annotate Lib/functools.py @ 87690:66c1c9f32567 default tip

Add use_weakref option to functools.lru_cache The use_weakref option makes lru_cache create weak references to the function arguments when creating the cache key, which prevents them from staying in the memory forever even after all other references to them are gone. This is a proof of concept for http://bugs.python.org/issue19859
author Radomir Dopieralski <devel@sheep.art.pl>
date Tue, 03 Dec 2013 16:02:48 +0100
parents ac1685661b07
children
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
rev   line source
38673
a19c20c5e5c7 Merge the rest of the trunk.
Thomas Wouters <thomas@python.org>
parents: 38669
diff changeset
1 """functools.py - Tools for working with functions and callable objects
38669
19fd6141940d Partially merge trunk into p3yk. The removal of Mac/Tools is confusing svn
Thomas Wouters <thomas@python.org>
parents:
diff changeset
2 """
19fd6141940d Partially merge trunk into p3yk. The removal of Mac/Tools is confusing svn
Thomas Wouters <thomas@python.org>
parents:
diff changeset
3 # Python module wrapper for _functools C module
19fd6141940d Partially merge trunk into p3yk. The removal of Mac/Tools is confusing svn
Thomas Wouters <thomas@python.org>
parents:
diff changeset
4 # to allow utilities written in Python to be added
19fd6141940d Partially merge trunk into p3yk. The removal of Mac/Tools is confusing svn
Thomas Wouters <thomas@python.org>
parents:
diff changeset
5 # to the functools module.
84039
dfcb64f51f7b Add reference implementation for PEP 443
Łukasz Langa <lukasz@langa.pl>
parents: 82561
diff changeset
6 # Written by Nick Coghlan <ncoghlan at gmail.com>,
dfcb64f51f7b Add reference implementation for PEP 443
Łukasz Langa <lukasz@langa.pl>
parents: 82561
diff changeset
7 # Raymond Hettinger <python at rcn.com>,
dfcb64f51f7b Add reference implementation for PEP 443
Łukasz Langa <lukasz@langa.pl>
parents: 82561
diff changeset
8 # and Ɓukasz Langa <lukasz at langa.pl>.
dfcb64f51f7b Add reference implementation for PEP 443
Łukasz Langa <lukasz@langa.pl>
parents: 82561
diff changeset
9 # Copyright (C) 2006-2013 Python Software Foundation.
38673
a19c20c5e5c7 Merge the rest of the trunk.
Thomas Wouters <thomas@python.org>
parents: 38669
diff changeset
10 # See C source code for _functools credits/copyright
38669
19fd6141940d Partially merge trunk into p3yk. The removal of Mac/Tools is confusing svn
Thomas Wouters <thomas@python.org>
parents:
diff changeset
11
63370
c55876a6fa3c Re-commit r83327 now that the release is done.
Georg Brandl <georg@python.org>
parents: 63357
diff changeset
12 __all__ = ['update_wrapper', 'wraps', 'WRAPPER_ASSIGNMENTS', 'WRAPPER_UPDATES',
84039
dfcb64f51f7b Add reference implementation for PEP 443
Łukasz Langa <lukasz@langa.pl>
parents: 82561
diff changeset
13 'total_ordering', 'cmp_to_key', 'lru_cache', 'reduce', 'partial',
86921
ac1685661b07 Fix functools.partialmethod docs and __all__
Nick Coghlan <ncoghlan@gmail.com>
parents: 86867
diff changeset
14 'partialmethod', 'singledispatch']
63370
c55876a6fa3c Re-commit r83327 now that the release is done.
Georg Brandl <georg@python.org>
parents: 63357
diff changeset
15
80421
fcfaca024160 Issue #12428: Add a pure Python implementation of functools.partial().
Antoine Pitrou <solipsis@pitrou.net>
parents: 77336
diff changeset
16 try:
fcfaca024160 Issue #12428: Add a pure Python implementation of functools.partial().
Antoine Pitrou <solipsis@pitrou.net>
parents: 77336
diff changeset
17 from _functools import reduce
84442
7769c4d72806 Issue #18200: Back out usage of ModuleNotFoundError (8d28d44f3a9a)
Brett Cannon <brett@python.org>
parents: 84411
diff changeset
18 except ImportError:
80421
fcfaca024160 Issue #12428: Add a pure Python implementation of functools.partial().
Antoine Pitrou <solipsis@pitrou.net>
parents: 77336
diff changeset
19 pass
84039
dfcb64f51f7b Add reference implementation for PEP 443
Łukasz Langa <lukasz@langa.pl>
parents: 82561
diff changeset
20 from abc import get_cache_token
75729
3b2856d8614b Improve the memory utilization (and speed) of functools.lru_cache().
Raymond Hettinger <python@rcn.com>
parents: 73943
diff changeset
21 from collections import namedtuple
86867
46d3c5539981 Issue #4331: Added functools.partialmethod
Nick Coghlan <ncoghlan@gmail.com>
parents: 85913
diff changeset
22 from types import MappingProxyType, MethodType
84039
dfcb64f51f7b Add reference implementation for PEP 443
Łukasz Langa <lukasz@langa.pl>
parents: 82561
diff changeset
23 from weakref import WeakKeyDictionary
64016
d8d0abe61e83 Add locks to make the caches well behaved in multi-threaded code.
Raymond Hettinger <python@rcn.com>
parents: 63823
diff changeset
24 try:
82437
1920422626a5 Don't deadlock on a reentrant call.
Raymond Hettinger <python@rcn.com>
parents: 77336
diff changeset
25 from _thread import RLock
64016
d8d0abe61e83 Add locks to make the caches well behaved in multi-threaded code.
Raymond Hettinger <python@rcn.com>
parents: 63823
diff changeset
26 except:
82450
e9732c25a018 Remove dependency on dummy_threading (to solve a bootstrap problem).
Raymond Hettinger <python@rcn.com>
parents: 82437
diff changeset
27 class RLock:
82558
1af9f7df3a96 Improve comments and variable names.
Raymond Hettinger <python@rcn.com>
parents: 82470
diff changeset
28 'Dummy reentrant lock for builds without threads'
82450
e9732c25a018 Remove dependency on dummy_threading (to solve a bootstrap problem).
Raymond Hettinger <python@rcn.com>
parents: 82437
diff changeset
29 def __enter__(self): pass
e9732c25a018 Remove dependency on dummy_threading (to solve a bootstrap problem).
Raymond Hettinger <python@rcn.com>
parents: 82437
diff changeset
30 def __exit__(self, exctype, excinst, exctb): pass
38673
a19c20c5e5c7 Merge the rest of the trunk.
Thomas Wouters <thomas@python.org>
parents: 38669
diff changeset
31
75776
66803fd0a6bc Section-off the source for better readability.
Raymond Hettinger <python@rcn.com>
parents: 75775
diff changeset
32
66803fd0a6bc Section-off the source for better readability.
Raymond Hettinger <python@rcn.com>
parents: 75775
diff changeset
33 ################################################################################
66803fd0a6bc Section-off the source for better readability.
Raymond Hettinger <python@rcn.com>
parents: 75775
diff changeset
34 ### update_wrapper() and wraps() decorator
66803fd0a6bc Section-off the source for better readability.
Raymond Hettinger <python@rcn.com>
parents: 75775
diff changeset
35 ################################################################################
66803fd0a6bc Section-off the source for better readability.
Raymond Hettinger <python@rcn.com>
parents: 75775
diff changeset
36
38673
a19c20c5e5c7 Merge the rest of the trunk.
Thomas Wouters <thomas@python.org>
parents: 38669
diff changeset
37 # update_wrapper() and wraps() are tools to help write
a19c20c5e5c7 Merge the rest of the trunk.
Thomas Wouters <thomas@python.org>
parents: 38669
diff changeset
38 # wrapper functions that can handle naive introspection
a19c20c5e5c7 Merge the rest of the trunk.
Thomas Wouters <thomas@python.org>
parents: 38669
diff changeset
39
73943
963e98f5ad31 Issue #13544: Add __qualname__ to functools.WRAPPER_ASSIGNMENTS.
Meador Inge <meadori@gmail.com>
parents: 73019
diff changeset
40 WRAPPER_ASSIGNMENTS = ('__module__', '__name__', '__qualname__', '__doc__',
963e98f5ad31 Issue #13544: Add __qualname__ to functools.WRAPPER_ASSIGNMENTS.
Meador Inge <meadori@gmail.com>
parents: 73019
diff changeset
41 '__annotations__')
38673
a19c20c5e5c7 Merge the rest of the trunk.
Thomas Wouters <thomas@python.org>
parents: 38669
diff changeset
42 WRAPPER_UPDATES = ('__dict__',)
a19c20c5e5c7 Merge the rest of the trunk.
Thomas Wouters <thomas@python.org>
parents: 38669
diff changeset
43 def update_wrapper(wrapper,
a19c20c5e5c7 Merge the rest of the trunk.
Thomas Wouters <thomas@python.org>
parents: 38669
diff changeset
44 wrapped,
a19c20c5e5c7 Merge the rest of the trunk.
Thomas Wouters <thomas@python.org>
parents: 38669
diff changeset
45 assigned = WRAPPER_ASSIGNMENTS,
a19c20c5e5c7 Merge the rest of the trunk.
Thomas Wouters <thomas@python.org>
parents: 38669
diff changeset
46 updated = WRAPPER_UPDATES):
a19c20c5e5c7 Merge the rest of the trunk.
Thomas Wouters <thomas@python.org>
parents: 38669
diff changeset
47 """Update a wrapper function to look like the wrapped function
38669
19fd6141940d Partially merge trunk into p3yk. The removal of Mac/Tools is confusing svn
Thomas Wouters <thomas@python.org>
parents:
diff changeset
48
38673
a19c20c5e5c7 Merge the rest of the trunk.
Thomas Wouters <thomas@python.org>
parents: 38669
diff changeset
49 wrapper is the function to be updated
a19c20c5e5c7 Merge the rest of the trunk.
Thomas Wouters <thomas@python.org>
parents: 38669
diff changeset
50 wrapped is the original function
a19c20c5e5c7 Merge the rest of the trunk.
Thomas Wouters <thomas@python.org>
parents: 38669
diff changeset
51 assigned is a tuple naming the attributes assigned directly
a19c20c5e5c7 Merge the rest of the trunk.
Thomas Wouters <thomas@python.org>
parents: 38669
diff changeset
52 from the wrapped function to the wrapper function (defaults to
a19c20c5e5c7 Merge the rest of the trunk.
Thomas Wouters <thomas@python.org>
parents: 38669
diff changeset
53 functools.WRAPPER_ASSIGNMENTS)
40450
cc992d75d5b3 Four months of trunk changes (including a few releases...)
Thomas Wouters <thomas@python.org>
parents: 39691
diff changeset
54 updated is a tuple naming the attributes of the wrapper that
38673
a19c20c5e5c7 Merge the rest of the trunk.
Thomas Wouters <thomas@python.org>
parents: 38669
diff changeset
55 are updated with the corresponding attribute from the wrapped
a19c20c5e5c7 Merge the rest of the trunk.
Thomas Wouters <thomas@python.org>
parents: 38669
diff changeset
56 function (defaults to functools.WRAPPER_UPDATES)
a19c20c5e5c7 Merge the rest of the trunk.
Thomas Wouters <thomas@python.org>
parents: 38669
diff changeset
57 """
a19c20c5e5c7 Merge the rest of the trunk.
Thomas Wouters <thomas@python.org>
parents: 38669
diff changeset
58 for attr in assigned:
64102
77bf58296c87 Document and test the resolution of issue 3445 (tolerate missing attributes in functools.update_wrapper, previously implemented as a side effect of the __annotations__ copying patch) and implement issue 9567 (add a __wrapped__ attribute when using update_wrapper)
Nick Coghlan <ncoghlan@gmail.com>
parents: 64030
diff changeset
59 try:
77bf58296c87 Document and test the resolution of issue 3445 (tolerate missing attributes in functools.update_wrapper, previously implemented as a side effect of the __annotations__ copying patch) and implement issue 9567 (add a __wrapped__ attribute when using update_wrapper)
Nick Coghlan <ncoghlan@gmail.com>
parents: 64030
diff changeset
60 value = getattr(wrapped, attr)
77bf58296c87 Document and test the resolution of issue 3445 (tolerate missing attributes in functools.update_wrapper, previously implemented as a side effect of the __annotations__ copying patch) and implement issue 9567 (add a __wrapped__ attribute when using update_wrapper)
Nick Coghlan <ncoghlan@gmail.com>
parents: 64030
diff changeset
61 except AttributeError:
77bf58296c87 Document and test the resolution of issue 3445 (tolerate missing attributes in functools.update_wrapper, previously implemented as a side effect of the __annotations__ copying patch) and implement issue 9567 (add a __wrapped__ attribute when using update_wrapper)
Nick Coghlan <ncoghlan@gmail.com>
parents: 64030
diff changeset
62 pass
77bf58296c87 Document and test the resolution of issue 3445 (tolerate missing attributes in functools.update_wrapper, previously implemented as a side effect of the __annotations__ copying patch) and implement issue 9567 (add a __wrapped__ attribute when using update_wrapper)
Nick Coghlan <ncoghlan@gmail.com>
parents: 64030
diff changeset
63 else:
77bf58296c87 Document and test the resolution of issue 3445 (tolerate missing attributes in functools.update_wrapper, previously implemented as a side effect of the __annotations__ copying patch) and implement issue 9567 (add a __wrapped__ attribute when using update_wrapper)
Nick Coghlan <ncoghlan@gmail.com>
parents: 64030
diff changeset
64 setattr(wrapper, attr, value)
38673
a19c20c5e5c7 Merge the rest of the trunk.
Thomas Wouters <thomas@python.org>
parents: 38669
diff changeset
65 for attr in updated:
40450
cc992d75d5b3 Four months of trunk changes (including a few releases...)
Thomas Wouters <thomas@python.org>
parents: 39691
diff changeset
66 getattr(wrapper, attr).update(getattr(wrapped, attr, {}))
84629
13b8fd71db46 Close issue 17482: don't overwrite __wrapped__
Nick Coghlan <ncoghlan@gmail.com>
parents: 84442
diff changeset
67 # Issue #17482: set __wrapped__ last so we don't inadvertently copy it
13b8fd71db46 Close issue 17482: don't overwrite __wrapped__
Nick Coghlan <ncoghlan@gmail.com>
parents: 84442
diff changeset
68 # from the wrapped function when updating __dict__
13b8fd71db46 Close issue 17482: don't overwrite __wrapped__
Nick Coghlan <ncoghlan@gmail.com>
parents: 84442
diff changeset
69 wrapper.__wrapped__ = wrapped
38673
a19c20c5e5c7 Merge the rest of the trunk.
Thomas Wouters <thomas@python.org>
parents: 38669
diff changeset
70 # Return the wrapper so this can be used as a decorator via partial()
a19c20c5e5c7 Merge the rest of the trunk.
Thomas Wouters <thomas@python.org>
parents: 38669
diff changeset
71 return wrapper
a19c20c5e5c7 Merge the rest of the trunk.
Thomas Wouters <thomas@python.org>
parents: 38669
diff changeset
72
a19c20c5e5c7 Merge the rest of the trunk.
Thomas Wouters <thomas@python.org>
parents: 38669
diff changeset
73 def wraps(wrapped,
a19c20c5e5c7 Merge the rest of the trunk.
Thomas Wouters <thomas@python.org>
parents: 38669
diff changeset
74 assigned = WRAPPER_ASSIGNMENTS,
a19c20c5e5c7 Merge the rest of the trunk.
Thomas Wouters <thomas@python.org>
parents: 38669
diff changeset
75 updated = WRAPPER_UPDATES):
a19c20c5e5c7 Merge the rest of the trunk.
Thomas Wouters <thomas@python.org>
parents: 38669
diff changeset
76 """Decorator factory to apply update_wrapper() to a wrapper function
a19c20c5e5c7 Merge the rest of the trunk.
Thomas Wouters <thomas@python.org>
parents: 38669
diff changeset
77
a19c20c5e5c7 Merge the rest of the trunk.
Thomas Wouters <thomas@python.org>
parents: 38669
diff changeset
78 Returns a decorator that invokes update_wrapper() with the decorated
a19c20c5e5c7 Merge the rest of the trunk.
Thomas Wouters <thomas@python.org>
parents: 38669
diff changeset
79 function as the wrapper argument and the arguments to wraps() as the
a19c20c5e5c7 Merge the rest of the trunk.
Thomas Wouters <thomas@python.org>
parents: 38669
diff changeset
80 remaining arguments. Default arguments are as for update_wrapper().
a19c20c5e5c7 Merge the rest of the trunk.
Thomas Wouters <thomas@python.org>
parents: 38669
diff changeset
81 This is a convenience function to simplify applying partial() to
a19c20c5e5c7 Merge the rest of the trunk.
Thomas Wouters <thomas@python.org>
parents: 38669
diff changeset
82 update_wrapper().
a19c20c5e5c7 Merge the rest of the trunk.
Thomas Wouters <thomas@python.org>
parents: 38669
diff changeset
83 """
a19c20c5e5c7 Merge the rest of the trunk.
Thomas Wouters <thomas@python.org>
parents: 38669
diff changeset
84 return partial(update_wrapper, wrapped=wrapped,
a19c20c5e5c7 Merge the rest of the trunk.
Thomas Wouters <thomas@python.org>
parents: 38669
diff changeset
85 assigned=assigned, updated=updated)
60370
3ce66c6922ab Forward port total_ordering() and cmp_to_key().
Raymond Hettinger <python@rcn.com>
parents: 40450
diff changeset
86
75776
66803fd0a6bc Section-off the source for better readability.
Raymond Hettinger <python@rcn.com>
parents: 75775
diff changeset
87
66803fd0a6bc Section-off the source for better readability.
Raymond Hettinger <python@rcn.com>
parents: 75775
diff changeset
88 ################################################################################
66803fd0a6bc Section-off the source for better readability.
Raymond Hettinger <python@rcn.com>
parents: 75775
diff changeset
89 ### total_ordering class decorator
66803fd0a6bc Section-off the source for better readability.
Raymond Hettinger <python@rcn.com>
parents: 75775
diff changeset
90 ################################################################################
66803fd0a6bc Section-off the source for better readability.
Raymond Hettinger <python@rcn.com>
parents: 75775
diff changeset
91
85913
ad9f207645ab Close #10042: functools.total_ordering now handles NotImplemented
Nick Coghlan <ncoghlan@gmail.com>
parents: 84629
diff changeset
92 # The correct way to indicate that a comparison operation doesn't
ad9f207645ab Close #10042: functools.total_ordering now handles NotImplemented
Nick Coghlan <ncoghlan@gmail.com>
parents: 84629
diff changeset
93 # recognise the other type is to return NotImplemented and let the
ad9f207645ab Close #10042: functools.total_ordering now handles NotImplemented
Nick Coghlan <ncoghlan@gmail.com>
parents: 84629
diff changeset
94 # interpreter handle raising TypeError if both operands return
ad9f207645ab Close #10042: functools.total_ordering now handles NotImplemented
Nick Coghlan <ncoghlan@gmail.com>
parents: 84629
diff changeset
95 # NotImplemented from their respective comparison methods
ad9f207645ab Close #10042: functools.total_ordering now handles NotImplemented
Nick Coghlan <ncoghlan@gmail.com>
parents: 84629
diff changeset
96 #
ad9f207645ab Close #10042: functools.total_ordering now handles NotImplemented
Nick Coghlan <ncoghlan@gmail.com>
parents: 84629
diff changeset
97 # This makes the implementation of total_ordering more complicated, since
ad9f207645ab Close #10042: functools.total_ordering now handles NotImplemented
Nick Coghlan <ncoghlan@gmail.com>
parents: 84629
diff changeset
98 # we need to be careful not to trigger infinite recursion when two
ad9f207645ab Close #10042: functools.total_ordering now handles NotImplemented
Nick Coghlan <ncoghlan@gmail.com>
parents: 84629
diff changeset
99 # different types that both use this decorator encounter each other.
ad9f207645ab Close #10042: functools.total_ordering now handles NotImplemented
Nick Coghlan <ncoghlan@gmail.com>
parents: 84629
diff changeset
100 #
ad9f207645ab Close #10042: functools.total_ordering now handles NotImplemented
Nick Coghlan <ncoghlan@gmail.com>
parents: 84629
diff changeset
101 # For example, if a type implements __lt__, it's natural to define
ad9f207645ab Close #10042: functools.total_ordering now handles NotImplemented
Nick Coghlan <ncoghlan@gmail.com>
parents: 84629
diff changeset
102 # __gt__ as something like:
ad9f207645ab Close #10042: functools.total_ordering now handles NotImplemented
Nick Coghlan <ncoghlan@gmail.com>
parents: 84629
diff changeset
103 #
ad9f207645ab Close #10042: functools.total_ordering now handles NotImplemented
Nick Coghlan <ncoghlan@gmail.com>
parents: 84629
diff changeset
104 # lambda self, other: not self < other and not self == other
ad9f207645ab Close #10042: functools.total_ordering now handles NotImplemented
Nick Coghlan <ncoghlan@gmail.com>
parents: 84629
diff changeset
105 #
ad9f207645ab Close #10042: functools.total_ordering now handles NotImplemented
Nick Coghlan <ncoghlan@gmail.com>
parents: 84629
diff changeset
106 # However, using the operator syntax like that ends up invoking the full
ad9f207645ab Close #10042: functools.total_ordering now handles NotImplemented
Nick Coghlan <ncoghlan@gmail.com>
parents: 84629
diff changeset
107 # type checking machinery again and means we can end up bouncing back and
ad9f207645ab Close #10042: functools.total_ordering now handles NotImplemented
Nick Coghlan <ncoghlan@gmail.com>
parents: 84629
diff changeset
108 # forth between the two operands until we run out of stack space.
ad9f207645ab Close #10042: functools.total_ordering now handles NotImplemented
Nick Coghlan <ncoghlan@gmail.com>
parents: 84629
diff changeset
109 #
ad9f207645ab Close #10042: functools.total_ordering now handles NotImplemented
Nick Coghlan <ncoghlan@gmail.com>
parents: 84629
diff changeset
110 # The solution is to define helper functions that invoke the appropriate
ad9f207645ab Close #10042: functools.total_ordering now handles NotImplemented
Nick Coghlan <ncoghlan@gmail.com>
parents: 84629
diff changeset
111 # magic methods directly, ensuring we only try each operand once, and
ad9f207645ab Close #10042: functools.total_ordering now handles NotImplemented
Nick Coghlan <ncoghlan@gmail.com>
parents: 84629
diff changeset
112 # return NotImplemented immediately if it is returned from the
ad9f207645ab Close #10042: functools.total_ordering now handles NotImplemented
Nick Coghlan <ncoghlan@gmail.com>
parents: 84629
diff changeset
113 # underlying user provided method. Using this scheme, the __gt__ derived
ad9f207645ab Close #10042: functools.total_ordering now handles NotImplemented
Nick Coghlan <ncoghlan@gmail.com>
parents: 84629
diff changeset
114 # from a user provided __lt__ becomes:
ad9f207645ab Close #10042: functools.total_ordering now handles NotImplemented
Nick Coghlan <ncoghlan@gmail.com>
parents: 84629
diff changeset
115 #
ad9f207645ab Close #10042: functools.total_ordering now handles NotImplemented
Nick Coghlan <ncoghlan@gmail.com>
parents: 84629
diff changeset
116 # lambda self, other: _not_op_and_not_eq(self.__lt__, self, other))
ad9f207645ab Close #10042: functools.total_ordering now handles NotImplemented
Nick Coghlan <ncoghlan@gmail.com>
parents: 84629
diff changeset
117
ad9f207645ab Close #10042: functools.total_ordering now handles NotImplemented
Nick Coghlan <ncoghlan@gmail.com>
parents: 84629
diff changeset
118 def _not_op(op, other):
ad9f207645ab Close #10042: functools.total_ordering now handles NotImplemented
Nick Coghlan <ncoghlan@gmail.com>
parents: 84629
diff changeset
119 # "not a < b" handles "a >= b"
ad9f207645ab Close #10042: functools.total_ordering now handles NotImplemented
Nick Coghlan <ncoghlan@gmail.com>
parents: 84629
diff changeset
120 # "not a <= b" handles "a > b"
ad9f207645ab Close #10042: functools.total_ordering now handles NotImplemented
Nick Coghlan <ncoghlan@gmail.com>
parents: 84629
diff changeset
121 # "not a >= b" handles "a < b"
ad9f207645ab Close #10042: functools.total_ordering now handles NotImplemented
Nick Coghlan <ncoghlan@gmail.com>
parents: 84629
diff changeset
122 # "not a > b" handles "a <= b"
ad9f207645ab Close #10042: functools.total_ordering now handles NotImplemented
Nick Coghlan <ncoghlan@gmail.com>
parents: 84629
diff changeset
123 op_result = op(other)
ad9f207645ab Close #10042: functools.total_ordering now handles NotImplemented
Nick Coghlan <ncoghlan@gmail.com>
parents: 84629
diff changeset
124 if op_result is NotImplemented:
ad9f207645ab Close #10042: functools.total_ordering now handles NotImplemented
Nick Coghlan <ncoghlan@gmail.com>
parents: 84629
diff changeset
125 return NotImplemented
ad9f207645ab Close #10042: functools.total_ordering now handles NotImplemented
Nick Coghlan <ncoghlan@gmail.com>
parents: 84629
diff changeset
126 return not op_result
ad9f207645ab Close #10042: functools.total_ordering now handles NotImplemented
Nick Coghlan <ncoghlan@gmail.com>
parents: 84629
diff changeset
127
ad9f207645ab Close #10042: functools.total_ordering now handles NotImplemented
Nick Coghlan <ncoghlan@gmail.com>
parents: 84629
diff changeset
128 def _op_or_eq(op, self, other):
ad9f207645ab Close #10042: functools.total_ordering now handles NotImplemented
Nick Coghlan <ncoghlan@gmail.com>
parents: 84629
diff changeset
129 # "a < b or a == b" handles "a <= b"
ad9f207645ab Close #10042: functools.total_ordering now handles NotImplemented
Nick Coghlan <ncoghlan@gmail.com>
parents: 84629
diff changeset
130 # "a > b or a == b" handles "a >= b"
ad9f207645ab Close #10042: functools.total_ordering now handles NotImplemented
Nick Coghlan <ncoghlan@gmail.com>
parents: 84629
diff changeset
131 op_result = op(other)
ad9f207645ab Close #10042: functools.total_ordering now handles NotImplemented
Nick Coghlan <ncoghlan@gmail.com>
parents: 84629
diff changeset
132 if op_result is NotImplemented:
ad9f207645ab Close #10042: functools.total_ordering now handles NotImplemented
Nick Coghlan <ncoghlan@gmail.com>
parents: 84629
diff changeset
133 return NotImplemented
ad9f207645ab Close #10042: functools.total_ordering now handles NotImplemented
Nick Coghlan <ncoghlan@gmail.com>
parents: 84629
diff changeset
134 return op_result or self == other
ad9f207645ab Close #10042: functools.total_ordering now handles NotImplemented
Nick Coghlan <ncoghlan@gmail.com>
parents: 84629
diff changeset
135
ad9f207645ab Close #10042: functools.total_ordering now handles NotImplemented
Nick Coghlan <ncoghlan@gmail.com>
parents: 84629
diff changeset
136 def _not_op_and_not_eq(op, self, other):
ad9f207645ab Close #10042: functools.total_ordering now handles NotImplemented
Nick Coghlan <ncoghlan@gmail.com>
parents: 84629
diff changeset
137 # "not (a < b or a == b)" handles "a > b"
ad9f207645ab Close #10042: functools.total_ordering now handles NotImplemented
Nick Coghlan <ncoghlan@gmail.com>
parents: 84629
diff changeset
138 # "not a < b and a != b" is equivalent
ad9f207645ab Close #10042: functools.total_ordering now handles NotImplemented
Nick Coghlan <ncoghlan@gmail.com>
parents: 84629
diff changeset
139 # "not (a > b or a == b)" handles "a < b"
ad9f207645ab Close #10042: functools.total_ordering now handles NotImplemented
Nick Coghlan <ncoghlan@gmail.com>
parents: 84629
diff changeset
140 # "not a > b and a != b" is equivalent
ad9f207645ab Close #10042: functools.total_ordering now handles NotImplemented
Nick Coghlan <ncoghlan@gmail.com>
parents: 84629
diff changeset
141 op_result = op(other)
ad9f207645ab Close #10042: functools.total_ordering now handles NotImplemented
Nick Coghlan <ncoghlan@gmail.com>
parents: 84629
diff changeset
142 if op_result is NotImplemented:
ad9f207645ab Close #10042: functools.total_ordering now handles NotImplemented
Nick Coghlan <ncoghlan@gmail.com>
parents: 84629
diff changeset
143 return NotImplemented
ad9f207645ab Close #10042: functools.total_ordering now handles NotImplemented
Nick Coghlan <ncoghlan@gmail.com>
parents: 84629
diff changeset
144 return not op_result and self != other
ad9f207645ab Close #10042: functools.total_ordering now handles NotImplemented
Nick Coghlan <ncoghlan@gmail.com>
parents: 84629
diff changeset
145
ad9f207645ab Close #10042: functools.total_ordering now handles NotImplemented
Nick Coghlan <ncoghlan@gmail.com>
parents: 84629
diff changeset
146 def _not_op_or_eq(op, self, other):
ad9f207645ab Close #10042: functools.total_ordering now handles NotImplemented
Nick Coghlan <ncoghlan@gmail.com>
parents: 84629
diff changeset
147 # "not a <= b or a == b" handles "a >= b"
ad9f207645ab Close #10042: functools.total_ordering now handles NotImplemented
Nick Coghlan <ncoghlan@gmail.com>
parents: 84629
diff changeset
148 # "not a >= b or a == b" handles "a <= b"
ad9f207645ab Close #10042: functools.total_ordering now handles NotImplemented
Nick Coghlan <ncoghlan@gmail.com>
parents: 84629
diff changeset
149 op_result = op(other)
ad9f207645ab Close #10042: functools.total_ordering now handles NotImplemented
Nick Coghlan <ncoghlan@gmail.com>
parents: 84629
diff changeset
150 if op_result is NotImplemented:
ad9f207645ab Close #10042: functools.total_ordering now handles NotImplemented
Nick Coghlan <ncoghlan@gmail.com>
parents: 84629
diff changeset
151 return NotImplemented
ad9f207645ab Close #10042: functools.total_ordering now handles NotImplemented
Nick Coghlan <ncoghlan@gmail.com>
parents: 84629
diff changeset
152 return not op_result or self == other
ad9f207645ab Close #10042: functools.total_ordering now handles NotImplemented
Nick Coghlan <ncoghlan@gmail.com>
parents: 84629
diff changeset
153
ad9f207645ab Close #10042: functools.total_ordering now handles NotImplemented
Nick Coghlan <ncoghlan@gmail.com>
parents: 84629
diff changeset
154 def _op_and_not_eq(op, self, other):
ad9f207645ab Close #10042: functools.total_ordering now handles NotImplemented
Nick Coghlan <ncoghlan@gmail.com>
parents: 84629
diff changeset
155 # "a <= b and not a == b" handles "a < b"
ad9f207645ab Close #10042: functools.total_ordering now handles NotImplemented
Nick Coghlan <ncoghlan@gmail.com>
parents: 84629
diff changeset
156 # "a >= b and not a == b" handles "a > b"
ad9f207645ab Close #10042: functools.total_ordering now handles NotImplemented
Nick Coghlan <ncoghlan@gmail.com>
parents: 84629
diff changeset
157 op_result = op(other)
ad9f207645ab Close #10042: functools.total_ordering now handles NotImplemented
Nick Coghlan <ncoghlan@gmail.com>
parents: 84629
diff changeset
158 if op_result is NotImplemented:
ad9f207645ab Close #10042: functools.total_ordering now handles NotImplemented
Nick Coghlan <ncoghlan@gmail.com>
parents: 84629
diff changeset
159 return NotImplemented
ad9f207645ab Close #10042: functools.total_ordering now handles NotImplemented
Nick Coghlan <ncoghlan@gmail.com>
parents: 84629
diff changeset
160 return op_result and self != other
ad9f207645ab Close #10042: functools.total_ordering now handles NotImplemented
Nick Coghlan <ncoghlan@gmail.com>
parents: 84629
diff changeset
161
60370
3ce66c6922ab Forward port total_ordering() and cmp_to_key().
Raymond Hettinger <python@rcn.com>
parents: 40450
diff changeset
162 def total_ordering(cls):
61761
82a4483d9c4a Merged revisions 80068 via svnmerge from
Georg Brandl <georg@python.org>
parents: 60479
diff changeset
163 """Class decorator that fills in missing ordering methods"""
60370
3ce66c6922ab Forward port total_ordering() and cmp_to_key().
Raymond Hettinger <python@rcn.com>
parents: 40450
diff changeset
164 convert = {
85913
ad9f207645ab Close #10042: functools.total_ordering now handles NotImplemented
Nick Coghlan <ncoghlan@gmail.com>
parents: 84629
diff changeset
165 '__lt__': [('__gt__', lambda self, other: _not_op_and_not_eq(self.__lt__, self, other)),
ad9f207645ab Close #10042: functools.total_ordering now handles NotImplemented
Nick Coghlan <ncoghlan@gmail.com>
parents: 84629
diff changeset
166 ('__le__', lambda self, other: _op_or_eq(self.__lt__, self, other)),
ad9f207645ab Close #10042: functools.total_ordering now handles NotImplemented
Nick Coghlan <ncoghlan@gmail.com>
parents: 84629
diff changeset
167 ('__ge__', lambda self, other: _not_op(self.__lt__, other))],
ad9f207645ab Close #10042: functools.total_ordering now handles NotImplemented
Nick Coghlan <ncoghlan@gmail.com>
parents: 84629
diff changeset
168 '__le__': [('__ge__', lambda self, other: _not_op_or_eq(self.__le__, self, other)),
ad9f207645ab Close #10042: functools.total_ordering now handles NotImplemented
Nick Coghlan <ncoghlan@gmail.com>
parents: 84629
diff changeset
169 ('__lt__', lambda self, other: _op_and_not_eq(self.__le__, self, other)),
ad9f207645ab Close #10042: functools.total_ordering now handles NotImplemented
Nick Coghlan <ncoghlan@gmail.com>
parents: 84629
diff changeset
170 ('__gt__', lambda self, other: _not_op(self.__le__, other))],
ad9f207645ab Close #10042: functools.total_ordering now handles NotImplemented
Nick Coghlan <ncoghlan@gmail.com>
parents: 84629
diff changeset
171 '__gt__': [('__lt__', lambda self, other: _not_op_and_not_eq(self.__gt__, self, other)),
ad9f207645ab Close #10042: functools.total_ordering now handles NotImplemented
Nick Coghlan <ncoghlan@gmail.com>
parents: 84629
diff changeset
172 ('__ge__', lambda self, other: _op_or_eq(self.__gt__, self, other)),
ad9f207645ab Close #10042: functools.total_ordering now handles NotImplemented
Nick Coghlan <ncoghlan@gmail.com>
parents: 84629
diff changeset
173 ('__le__', lambda self, other: _not_op(self.__gt__, other))],
ad9f207645ab Close #10042: functools.total_ordering now handles NotImplemented
Nick Coghlan <ncoghlan@gmail.com>
parents: 84629
diff changeset
174 '__ge__': [('__le__', lambda self, other: _not_op_or_eq(self.__ge__, self, other)),
ad9f207645ab Close #10042: functools.total_ordering now handles NotImplemented
Nick Coghlan <ncoghlan@gmail.com>
parents: 84629
diff changeset
175 ('__gt__', lambda self, other: _op_and_not_eq(self.__ge__, self, other)),
ad9f207645ab Close #10042: functools.total_ordering now handles NotImplemented
Nick Coghlan <ncoghlan@gmail.com>
parents: 84629
diff changeset
176 ('__lt__', lambda self, other: _not_op(self.__ge__, other))]
60370
3ce66c6922ab Forward port total_ordering() and cmp_to_key().
Raymond Hettinger <python@rcn.com>
parents: 40450
diff changeset
177 }
64776
985072cd31d0 Improve comment
Raymond Hettinger <python@rcn.com>
parents: 64755
diff changeset
178 # Find user-defined comparisons (not those inherited from object).
64755
f643d53c51bd Future proof total_ordering against changes in methods defined on object.
Raymond Hettinger <python@rcn.com>
parents: 64642
diff changeset
179 roots = [op for op in convert if getattr(cls, op, None) is not getattr(object, op, None)]
60479
805512329c75 Issue 8361: Remove assert from functools.total_ordering
Raymond Hettinger <python@rcn.com>
parents: 60370
diff changeset
180 if not roots:
805512329c75 Issue 8361: Remove assert from functools.total_ordering
Raymond Hettinger <python@rcn.com>
parents: 60370
diff changeset
181 raise ValueError('must define at least one ordering operation: < > <= >=')
805512329c75 Issue 8361: Remove assert from functools.total_ordering
Raymond Hettinger <python@rcn.com>
parents: 60370
diff changeset
182 root = max(roots) # prefer __lt__ to __le__ to __gt__ to __ge__
60370
3ce66c6922ab Forward port total_ordering() and cmp_to_key().
Raymond Hettinger <python@rcn.com>
parents: 40450
diff changeset
183 for opname, opfunc in convert[root]:
3ce66c6922ab Forward port total_ordering() and cmp_to_key().
Raymond Hettinger <python@rcn.com>
parents: 40450
diff changeset
184 if opname not in roots:
3ce66c6922ab Forward port total_ordering() and cmp_to_key().
Raymond Hettinger <python@rcn.com>
parents: 40450
diff changeset
185 opfunc.__name__ = opname
3ce66c6922ab Forward port total_ordering() and cmp_to_key().
Raymond Hettinger <python@rcn.com>
parents: 40450
diff changeset
186 opfunc.__doc__ = getattr(int, opname).__doc__
3ce66c6922ab Forward port total_ordering() and cmp_to_key().
Raymond Hettinger <python@rcn.com>
parents: 40450
diff changeset
187 setattr(cls, opname, opfunc)
3ce66c6922ab Forward port total_ordering() and cmp_to_key().
Raymond Hettinger <python@rcn.com>
parents: 40450
diff changeset
188 return cls
3ce66c6922ab Forward port total_ordering() and cmp_to_key().
Raymond Hettinger <python@rcn.com>
parents: 40450
diff changeset
189
75776
66803fd0a6bc Section-off the source for better readability.
Raymond Hettinger <python@rcn.com>
parents: 75775
diff changeset
190
66803fd0a6bc Section-off the source for better readability.
Raymond Hettinger <python@rcn.com>
parents: 75775
diff changeset
191 ################################################################################
66803fd0a6bc Section-off the source for better readability.
Raymond Hettinger <python@rcn.com>
parents: 75775
diff changeset
192 ### cmp_to_key() function converter
66803fd0a6bc Section-off the source for better readability.
Raymond Hettinger <python@rcn.com>
parents: 75775
diff changeset
193 ################################################################################
66803fd0a6bc Section-off the source for better readability.
Raymond Hettinger <python@rcn.com>
parents: 75775
diff changeset
194
60370
3ce66c6922ab Forward port total_ordering() and cmp_to_key().
Raymond Hettinger <python@rcn.com>
parents: 40450
diff changeset
195 def cmp_to_key(mycmp):
61761
82a4483d9c4a Merged revisions 80068 via svnmerge from
Georg Brandl <georg@python.org>
parents: 60479
diff changeset
196 """Convert a cmp= function into a key= function"""
60370
3ce66c6922ab Forward port total_ordering() and cmp_to_key().
Raymond Hettinger <python@rcn.com>
parents: 40450
diff changeset
197 class K(object):
68824
97799a54728e Issue #11628: cmp_to_key should use __slots__.
Raymond Hettinger <python@rcn.com>
parents: 68257
diff changeset
198 __slots__ = ['obj']
69862
9f58612bc334 Sync-up minor code edits with the default branch.
Raymond Hettinger <python@rcn.com>
parents: 69810
diff changeset
199 def __init__(self, obj):
60370
3ce66c6922ab Forward port total_ordering() and cmp_to_key().
Raymond Hettinger <python@rcn.com>
parents: 40450
diff changeset
200 self.obj = obj
3ce66c6922ab Forward port total_ordering() and cmp_to_key().
Raymond Hettinger <python@rcn.com>
parents: 40450
diff changeset
201 def __lt__(self, other):
3ce66c6922ab Forward port total_ordering() and cmp_to_key().
Raymond Hettinger <python@rcn.com>
parents: 40450
diff changeset
202 return mycmp(self.obj, other.obj) < 0
3ce66c6922ab Forward port total_ordering() and cmp_to_key().
Raymond Hettinger <python@rcn.com>
parents: 40450
diff changeset
203 def __gt__(self, other):
3ce66c6922ab Forward port total_ordering() and cmp_to_key().
Raymond Hettinger <python@rcn.com>
parents: 40450
diff changeset
204 return mycmp(self.obj, other.obj) > 0
3ce66c6922ab Forward port total_ordering() and cmp_to_key().
Raymond Hettinger <python@rcn.com>
parents: 40450
diff changeset
205 def __eq__(self, other):
3ce66c6922ab Forward port total_ordering() and cmp_to_key().
Raymond Hettinger <python@rcn.com>
parents: 40450
diff changeset
206 return mycmp(self.obj, other.obj) == 0
3ce66c6922ab Forward port total_ordering() and cmp_to_key().
Raymond Hettinger <python@rcn.com>
parents: 40450
diff changeset
207 def __le__(self, other):
3ce66c6922ab Forward port total_ordering() and cmp_to_key().
Raymond Hettinger <python@rcn.com>
parents: 40450
diff changeset
208 return mycmp(self.obj, other.obj) <= 0
3ce66c6922ab Forward port total_ordering() and cmp_to_key().
Raymond Hettinger <python@rcn.com>
parents: 40450
diff changeset
209 def __ge__(self, other):
3ce66c6922ab Forward port total_ordering() and cmp_to_key().
Raymond Hettinger <python@rcn.com>
parents: 40450
diff changeset
210 return mycmp(self.obj, other.obj) >= 0
3ce66c6922ab Forward port total_ordering() and cmp_to_key().
Raymond Hettinger <python@rcn.com>
parents: 40450
diff changeset
211 def __ne__(self, other):
3ce66c6922ab Forward port total_ordering() and cmp_to_key().
Raymond Hettinger <python@rcn.com>
parents: 40450
diff changeset
212 return mycmp(self.obj, other.obj) != 0
69810
2675415c57c1 Fix __hash__ in functools.cmp_to_key() to work with collections.Hashable.
Raymond Hettinger <python@rcn.com>
parents: 68824
diff changeset
213 __hash__ = None
60370
3ce66c6922ab Forward port total_ordering() and cmp_to_key().
Raymond Hettinger <python@rcn.com>
parents: 40450
diff changeset
214 return K
63370
c55876a6fa3c Re-commit r83327 now that the release is done.
Georg Brandl <georg@python.org>
parents: 63357
diff changeset
215
69150
a03fb2fc3ed8 Issue #11707: Fast C version of functools.cmp_to_key()
Raymond Hettinger <python@rcn.com>
parents: 68825
diff changeset
216 try:
a03fb2fc3ed8 Issue #11707: Fast C version of functools.cmp_to_key()
Raymond Hettinger <python@rcn.com>
parents: 68825
diff changeset
217 from _functools import cmp_to_key
84442
7769c4d72806 Issue #18200: Back out usage of ModuleNotFoundError (8d28d44f3a9a)
Brett Cannon <brett@python.org>
parents: 84411
diff changeset
218 except ImportError:
69150
a03fb2fc3ed8 Issue #11707: Fast C version of functools.cmp_to_key()
Raymond Hettinger <python@rcn.com>
parents: 68825
diff changeset
219 pass
a03fb2fc3ed8 Issue #11707: Fast C version of functools.cmp_to_key()
Raymond Hettinger <python@rcn.com>
parents: 68825
diff changeset
220
75776
66803fd0a6bc Section-off the source for better readability.
Raymond Hettinger <python@rcn.com>
parents: 75775
diff changeset
221
66803fd0a6bc Section-off the source for better readability.
Raymond Hettinger <python@rcn.com>
parents: 75775
diff changeset
222 ################################################################################
80421
fcfaca024160 Issue #12428: Add a pure Python implementation of functools.partial().
Antoine Pitrou <solipsis@pitrou.net>
parents: 77336
diff changeset
223 ### partial() argument application
fcfaca024160 Issue #12428: Add a pure Python implementation of functools.partial().
Antoine Pitrou <solipsis@pitrou.net>
parents: 77336
diff changeset
224 ################################################################################
fcfaca024160 Issue #12428: Add a pure Python implementation of functools.partial().
Antoine Pitrou <solipsis@pitrou.net>
parents: 77336
diff changeset
225
86867
46d3c5539981 Issue #4331: Added functools.partialmethod
Nick Coghlan <ncoghlan@gmail.com>
parents: 85913
diff changeset
226 # Purely functional, no descriptor behaviour
80421
fcfaca024160 Issue #12428: Add a pure Python implementation of functools.partial().
Antoine Pitrou <solipsis@pitrou.net>
parents: 77336
diff changeset
227 def partial(func, *args, **keywords):
86867
46d3c5539981 Issue #4331: Added functools.partialmethod
Nick Coghlan <ncoghlan@gmail.com>
parents: 85913
diff changeset
228 """New function with partial application of the given arguments
80421
fcfaca024160 Issue #12428: Add a pure Python implementation of functools.partial().
Antoine Pitrou <solipsis@pitrou.net>
parents: 77336
diff changeset
229 and keywords.
fcfaca024160 Issue #12428: Add a pure Python implementation of functools.partial().
Antoine Pitrou <solipsis@pitrou.net>
parents: 77336
diff changeset
230 """
fcfaca024160 Issue #12428: Add a pure Python implementation of functools.partial().
Antoine Pitrou <solipsis@pitrou.net>
parents: 77336
diff changeset
231 def newfunc(*fargs, **fkeywords):
fcfaca024160 Issue #12428: Add a pure Python implementation of functools.partial().
Antoine Pitrou <solipsis@pitrou.net>
parents: 77336
diff changeset
232 newkeywords = keywords.copy()
fcfaca024160 Issue #12428: Add a pure Python implementation of functools.partial().
Antoine Pitrou <solipsis@pitrou.net>
parents: 77336
diff changeset
233 newkeywords.update(fkeywords)
fcfaca024160 Issue #12428: Add a pure Python implementation of functools.partial().
Antoine Pitrou <solipsis@pitrou.net>
parents: 77336
diff changeset
234 return func(*(args + fargs), **newkeywords)
fcfaca024160 Issue #12428: Add a pure Python implementation of functools.partial().
Antoine Pitrou <solipsis@pitrou.net>
parents: 77336
diff changeset
235 newfunc.func = func
fcfaca024160 Issue #12428: Add a pure Python implementation of functools.partial().
Antoine Pitrou <solipsis@pitrou.net>
parents: 77336
diff changeset
236 newfunc.args = args
fcfaca024160 Issue #12428: Add a pure Python implementation of functools.partial().
Antoine Pitrou <solipsis@pitrou.net>
parents: 77336
diff changeset
237 newfunc.keywords = keywords
fcfaca024160 Issue #12428: Add a pure Python implementation of functools.partial().
Antoine Pitrou <solipsis@pitrou.net>
parents: 77336
diff changeset
238 return newfunc
fcfaca024160 Issue #12428: Add a pure Python implementation of functools.partial().
Antoine Pitrou <solipsis@pitrou.net>
parents: 77336
diff changeset
239
fcfaca024160 Issue #12428: Add a pure Python implementation of functools.partial().
Antoine Pitrou <solipsis@pitrou.net>
parents: 77336
diff changeset
240 try:
fcfaca024160 Issue #12428: Add a pure Python implementation of functools.partial().
Antoine Pitrou <solipsis@pitrou.net>
parents: 77336
diff changeset
241 from _functools import partial
84442
7769c4d72806 Issue #18200: Back out usage of ModuleNotFoundError (8d28d44f3a9a)
Brett Cannon <brett@python.org>
parents: 84411
diff changeset
242 except ImportError:
80421
fcfaca024160 Issue #12428: Add a pure Python implementation of functools.partial().
Antoine Pitrou <solipsis@pitrou.net>
parents: 77336
diff changeset
243 pass
fcfaca024160 Issue #12428: Add a pure Python implementation of functools.partial().
Antoine Pitrou <solipsis@pitrou.net>
parents: 77336
diff changeset
244
86867
46d3c5539981 Issue #4331: Added functools.partialmethod
Nick Coghlan <ncoghlan@gmail.com>
parents: 85913
diff changeset
245 # Descriptor version
46d3c5539981 Issue #4331: Added functools.partialmethod
Nick Coghlan <ncoghlan@gmail.com>
parents: 85913
diff changeset
246 class partialmethod(object):
46d3c5539981 Issue #4331: Added functools.partialmethod
Nick Coghlan <ncoghlan@gmail.com>
parents: 85913
diff changeset
247 """Method descriptor with partial application of the given arguments
46d3c5539981 Issue #4331: Added functools.partialmethod
Nick Coghlan <ncoghlan@gmail.com>
parents: 85913
diff changeset
248 and keywords.
46d3c5539981 Issue #4331: Added functools.partialmethod
Nick Coghlan <ncoghlan@gmail.com>
parents: 85913
diff changeset
249
46d3c5539981 Issue #4331: Added functools.partialmethod
Nick Coghlan <ncoghlan@gmail.com>
parents: 85913
diff changeset
250 Supports wrapping existing descriptors and handles non-descriptor
46d3c5539981 Issue #4331: Added functools.partialmethod
Nick Coghlan <ncoghlan@gmail.com>
parents: 85913
diff changeset
251 callables as instance methods.
46d3c5539981 Issue #4331: Added functools.partialmethod
Nick Coghlan <ncoghlan@gmail.com>
parents: 85913
diff changeset
252 """
46d3c5539981 Issue #4331: Added functools.partialmethod
Nick Coghlan <ncoghlan@gmail.com>
parents: 85913
diff changeset
253
46d3c5539981 Issue #4331: Added functools.partialmethod
Nick Coghlan <ncoghlan@gmail.com>
parents: 85913
diff changeset
254 def __init__(self, func, *args, **keywords):
46d3c5539981 Issue #4331: Added functools.partialmethod
Nick Coghlan <ncoghlan@gmail.com>
parents: 85913
diff changeset
255 if not callable(func) and not hasattr(func, "__get__"):
46d3c5539981 Issue #4331: Added functools.partialmethod
Nick Coghlan <ncoghlan@gmail.com>
parents: 85913
diff changeset
256 raise TypeError("{!r} is not callable or a descriptor"
46d3c5539981 Issue #4331: Added functools.partialmethod
Nick Coghlan <ncoghlan@gmail.com>
parents: 85913
diff changeset
257 .format(func))
46d3c5539981 Issue #4331: Added functools.partialmethod
Nick Coghlan <ncoghlan@gmail.com>
parents: 85913
diff changeset
258
46d3c5539981 Issue #4331: Added functools.partialmethod
Nick Coghlan <ncoghlan@gmail.com>
parents: 85913
diff changeset
259 # func could be a descriptor like classmethod which isn't callable,
46d3c5539981 Issue #4331: Added functools.partialmethod
Nick Coghlan <ncoghlan@gmail.com>
parents: 85913
diff changeset
260 # so we can't inherit from partial (it verifies func is callable)
46d3c5539981 Issue #4331: Added functools.partialmethod
Nick Coghlan <ncoghlan@gmail.com>
parents: 85913
diff changeset
261 if isinstance(func, partialmethod):
46d3c5539981 Issue #4331: Added functools.partialmethod
Nick Coghlan <ncoghlan@gmail.com>
parents: 85913
diff changeset
262 # flattening is mandatory in order to place cls/self before all
46d3c5539981 Issue #4331: Added functools.partialmethod
Nick Coghlan <ncoghlan@gmail.com>
parents: 85913
diff changeset
263 # other arguments
46d3c5539981 Issue #4331: Added functools.partialmethod
Nick Coghlan <ncoghlan@gmail.com>
parents: 85913
diff changeset
264 # it's also more efficient since only one function will be called
46d3c5539981 Issue #4331: Added functools.partialmethod
Nick Coghlan <ncoghlan@gmail.com>
parents: 85913
diff changeset
265 self.func = func.func
46d3c5539981 Issue #4331: Added functools.partialmethod
Nick Coghlan <ncoghlan@gmail.com>
parents: 85913
diff changeset
266 self.args = func.args + args
46d3c5539981 Issue #4331: Added functools.partialmethod
Nick Coghlan <ncoghlan@gmail.com>
parents: 85913
diff changeset
267 self.keywords = func.keywords.copy()
46d3c5539981 Issue #4331: Added functools.partialmethod
Nick Coghlan <ncoghlan@gmail.com>
parents: 85913
diff changeset
268 self.keywords.update(keywords)
46d3c5539981 Issue #4331: Added functools.partialmethod
Nick Coghlan <ncoghlan@gmail.com>
parents: 85913
diff changeset
269 else:
46d3c5539981 Issue #4331: Added functools.partialmethod
Nick Coghlan <ncoghlan@gmail.com>
parents: 85913
diff changeset
270 self.func = func
46d3c5539981 Issue #4331: Added functools.partialmethod
Nick Coghlan <ncoghlan@gmail.com>
parents: 85913
diff changeset
271 self.args = args
46d3c5539981 Issue #4331: Added functools.partialmethod
Nick Coghlan <ncoghlan@gmail.com>
parents: 85913
diff changeset
272 self.keywords = keywords
46d3c5539981 Issue #4331: Added functools.partialmethod
Nick Coghlan <ncoghlan@gmail.com>
parents: 85913
diff changeset
273
46d3c5539981 Issue #4331: Added functools.partialmethod
Nick Coghlan <ncoghlan@gmail.com>
parents: 85913
diff changeset
274 def __repr__(self):
46d3c5539981 Issue #4331: Added functools.partialmethod
Nick Coghlan <ncoghlan@gmail.com>
parents: 85913
diff changeset
275 args = ", ".join(map(repr, self.args))
46d3c5539981 Issue #4331: Added functools.partialmethod
Nick Coghlan <ncoghlan@gmail.com>
parents: 85913
diff changeset
276 keywords = ", ".join("{}={!r}".format(k, v)
46d3c5539981 Issue #4331: Added functools.partialmethod
Nick Coghlan <ncoghlan@gmail.com>
parents: 85913
diff changeset
277 for k, v in self.keywords.items())
46d3c5539981 Issue #4331: Added functools.partialmethod
Nick Coghlan <ncoghlan@gmail.com>
parents: 85913
diff changeset
278 format_string = "{module}.{cls}({func}, {args}, {keywords})"
46d3c5539981 Issue #4331: Added functools.partialmethod
Nick Coghlan <ncoghlan@gmail.com>
parents: 85913
diff changeset
279 return format_string.format(module=self.__class__.__module__,
46d3c5539981 Issue #4331: Added functools.partialmethod
Nick Coghlan <ncoghlan@gmail.com>
parents: 85913
diff changeset
280 cls=self.__class__.__name__,
46d3c5539981 Issue #4331: Added functools.partialmethod
Nick Coghlan <ncoghlan@gmail.com>
parents: 85913
diff changeset
281 func=self.func,
46d3c5539981 Issue #4331: Added functools.partialmethod
Nick Coghlan <ncoghlan@gmail.com>
parents: 85913
diff changeset
282 args=args,
46d3c5539981 Issue #4331: Added functools.partialmethod
Nick Coghlan <ncoghlan@gmail.com>
parents: 85913
diff changeset
283 keywords=keywords)
46d3c5539981 Issue #4331: Added functools.partialmethod
Nick Coghlan <ncoghlan@gmail.com>
parents: 85913
diff changeset
284
46d3c5539981 Issue #4331: Added functools.partialmethod
Nick Coghlan <ncoghlan@gmail.com>
parents: 85913
diff changeset
285 def _make_unbound_method(self):
46d3c5539981 Issue #4331: Added functools.partialmethod
Nick Coghlan <ncoghlan@gmail.com>
parents: 85913
diff changeset
286 def _method(*args, **keywords):
46d3c5539981 Issue #4331: Added functools.partialmethod
Nick Coghlan <ncoghlan@gmail.com>
parents: 85913
diff changeset
287 call_keywords = self.keywords.copy()
46d3c5539981 Issue #4331: Added functools.partialmethod
Nick Coghlan <ncoghlan@gmail.com>
parents: 85913
diff changeset
288 call_keywords.update(keywords)
46d3c5539981 Issue #4331: Added functools.partialmethod
Nick Coghlan <ncoghlan@gmail.com>
parents: 85913
diff changeset
289 cls_or_self, *rest = args
46d3c5539981 Issue #4331: Added functools.partialmethod
Nick Coghlan <ncoghlan@gmail.com>
parents: 85913
diff changeset
290 call_args = (cls_or_self,) + self.args + tuple(rest)
46d3c5539981 Issue #4331: Added functools.partialmethod
Nick Coghlan <ncoghlan@gmail.com>
parents: 85913
diff changeset
291 return self.func(*call_args, **call_keywords)
46d3c5539981 Issue #4331: Added functools.partialmethod
Nick Coghlan <ncoghlan@gmail.com>
parents: 85913
diff changeset
292 _method.__isabstractmethod__ = self.__isabstractmethod__
46d3c5539981 Issue #4331: Added functools.partialmethod
Nick Coghlan <ncoghlan@gmail.com>
parents: 85913
diff changeset
293 return _method
46d3c5539981 Issue #4331: Added functools.partialmethod
Nick Coghlan <ncoghlan@gmail.com>
parents: 85913
diff changeset
294
46d3c5539981 Issue #4331: Added functools.partialmethod
Nick Coghlan <ncoghlan@gmail.com>
parents: 85913
diff changeset
295 def __get__(self, obj, cls):
46d3c5539981 Issue #4331: Added functools.partialmethod
Nick Coghlan <ncoghlan@gmail.com>
parents: 85913
diff changeset
296 get = getattr(self.func, "__get__", None)
46d3c5539981 Issue #4331: Added functools.partialmethod
Nick Coghlan <ncoghlan@gmail.com>
parents: 85913
diff changeset
297 result = None
46d3c5539981 Issue #4331: Added functools.partialmethod
Nick Coghlan <ncoghlan@gmail.com>
parents: 85913
diff changeset
298 if get is not None:
46d3c5539981 Issue #4331: Added functools.partialmethod
Nick Coghlan <ncoghlan@gmail.com>
parents: 85913
diff changeset
299 new_func = get(obj, cls)
46d3c5539981 Issue #4331: Added functools.partialmethod
Nick Coghlan <ncoghlan@gmail.com>
parents: 85913
diff changeset
300 if new_func is not self.func:
46d3c5539981 Issue #4331: Added functools.partialmethod
Nick Coghlan <ncoghlan@gmail.com>
parents: 85913
diff changeset
301 # Assume __get__ returning something new indicates the
46d3c5539981 Issue #4331: Added functools.partialmethod
Nick Coghlan <ncoghlan@gmail.com>
parents: 85913
diff changeset
302 # creation of an appropriate callable
46d3c5539981 Issue #4331: Added functools.partialmethod
Nick Coghlan <ncoghlan@gmail.com>
parents: 85913
diff changeset
303 result = partial(new_func, *self.args, **self.keywords)
46d3c5539981 Issue #4331: Added functools.partialmethod
Nick Coghlan <ncoghlan@gmail.com>
parents: 85913
diff changeset
304 try:
46d3c5539981 Issue #4331: Added functools.partialmethod
Nick Coghlan <ncoghlan@gmail.com>
parents: 85913
diff changeset
305 result.__self__ = new_func.__self__
46d3c5539981 Issue #4331: Added functools.partialmethod
Nick Coghlan <ncoghlan@gmail.com>
parents: 85913
diff changeset
306 except AttributeError:
46d3c5539981 Issue #4331: Added functools.partialmethod
Nick Coghlan <ncoghlan@gmail.com>
parents: 85913
diff changeset
307 pass
46d3c5539981 Issue #4331: Added functools.partialmethod
Nick Coghlan <ncoghlan@gmail.com>
parents: 85913
diff changeset
308 if result is None:
46d3c5539981 Issue #4331: Added functools.partialmethod
Nick Coghlan <ncoghlan@gmail.com>
parents: 85913
diff changeset
309 # If the underlying descriptor didn't do anything, treat this
46d3c5539981 Issue #4331: Added functools.partialmethod
Nick Coghlan <ncoghlan@gmail.com>
parents: 85913
diff changeset
310 # like an instance method
46d3c5539981 Issue #4331: Added functools.partialmethod
Nick Coghlan <ncoghlan@gmail.com>
parents: 85913
diff changeset
311 result = self._make_unbound_method().__get__(obj, cls)
46d3c5539981 Issue #4331: Added functools.partialmethod
Nick Coghlan <ncoghlan@gmail.com>
parents: 85913
diff changeset
312 return result
46d3c5539981 Issue #4331: Added functools.partialmethod
Nick Coghlan <ncoghlan@gmail.com>
parents: 85913
diff changeset
313
46d3c5539981 Issue #4331: Added functools.partialmethod
Nick Coghlan <ncoghlan@gmail.com>
parents: 85913
diff changeset
314 @property
46d3c5539981 Issue #4331: Added functools.partialmethod
Nick Coghlan <ncoghlan@gmail.com>
parents: 85913
diff changeset
315 def __isabstractmethod__(self):
46d3c5539981 Issue #4331: Added functools.partialmethod
Nick Coghlan <ncoghlan@gmail.com>
parents: 85913
diff changeset
316 return getattr(self.func, "__isabstractmethod__", False)
46d3c5539981 Issue #4331: Added functools.partialmethod
Nick Coghlan <ncoghlan@gmail.com>
parents: 85913
diff changeset
317
80421
fcfaca024160 Issue #12428: Add a pure Python implementation of functools.partial().
Antoine Pitrou <solipsis@pitrou.net>
parents: 77336
diff changeset
318
fcfaca024160 Issue #12428: Add a pure Python implementation of functools.partial().
Antoine Pitrou <solipsis@pitrou.net>
parents: 77336
diff changeset
319 ################################################################################
75776
66803fd0a6bc Section-off the source for better readability.
Raymond Hettinger <python@rcn.com>
parents: 75775
diff changeset
320 ### LRU Cache function decorator
66803fd0a6bc Section-off the source for better readability.
Raymond Hettinger <python@rcn.com>
parents: 75775
diff changeset
321 ################################################################################
66803fd0a6bc Section-off the source for better readability.
Raymond Hettinger <python@rcn.com>
parents: 75775
diff changeset
322
75775
70672d21b9fd Minor beautification.
Raymond Hettinger <python@rcn.com>
parents: 75760
diff changeset
323 _CacheInfo = namedtuple("CacheInfo", ["hits", "misses", "maxsize", "currsize"])
66550
312b2916cfd4 Issue 10586: change the new functools.lru_cache implementation to expose the maximum and current cache sizes through the public statistics API. This API is now a single function that returns a named tuple.
Nick Coghlan <ncoghlan@gmail.com>
parents: 66441
diff changeset
324
77336
2d5ca0ea2aab Separate key creation logic from the sequence class that memoizes its hash value.
Raymond Hettinger <python@rcn.com>
parents: 77068
diff changeset
325 class _HashedSeq(list):
82558
1af9f7df3a96 Improve comments and variable names.
Raymond Hettinger <python@rcn.com>
parents: 82470
diff changeset
326 """ This class guarantees that hash() will be called no more than once
1af9f7df3a96 Improve comments and variable names.
Raymond Hettinger <python@rcn.com>
parents: 82470
diff changeset
327 per element. This is important because the lru_cache() will hash
1af9f7df3a96 Improve comments and variable names.
Raymond Hettinger <python@rcn.com>
parents: 82470
diff changeset
328 the key multiple times on a cache miss.
1af9f7df3a96 Improve comments and variable names.
Raymond Hettinger <python@rcn.com>
parents: 82470
diff changeset
329
1af9f7df3a96 Improve comments and variable names.
Raymond Hettinger <python@rcn.com>
parents: 82470
diff changeset
330 """
1af9f7df3a96 Improve comments and variable names.
Raymond Hettinger <python@rcn.com>
parents: 82470
diff changeset
331
76681
f981fe3b8bf7 Move make_key() out of the decorator body. Make keys that only need to be hashed once.
Raymond Hettinger <python@rcn.com>
parents: 76680
diff changeset
332 __slots__ = 'hashvalue'
f981fe3b8bf7 Move make_key() out of the decorator body. Make keys that only need to be hashed once.
Raymond Hettinger <python@rcn.com>
parents: 76680
diff changeset
333
77336
2d5ca0ea2aab Separate key creation logic from the sequence class that memoizes its hash value.
Raymond Hettinger <python@rcn.com>
parents: 77068
diff changeset
334 def __init__(self, tup, hash=hash):
2d5ca0ea2aab Separate key creation logic from the sequence class that memoizes its hash value.
Raymond Hettinger <python@rcn.com>
parents: 77068
diff changeset
335 self[:] = tup
2d5ca0ea2aab Separate key creation logic from the sequence class that memoizes its hash value.
Raymond Hettinger <python@rcn.com>
parents: 77068
diff changeset
336 self.hashvalue = hash(tup)
76681
f981fe3b8bf7 Move make_key() out of the decorator body. Make keys that only need to be hashed once.
Raymond Hettinger <python@rcn.com>
parents: 76680
diff changeset
337
f981fe3b8bf7 Move make_key() out of the decorator body. Make keys that only need to be hashed once.
Raymond Hettinger <python@rcn.com>
parents: 76680
diff changeset
338 def __hash__(self):
f981fe3b8bf7 Move make_key() out of the decorator body. Make keys that only need to be hashed once.
Raymond Hettinger <python@rcn.com>
parents: 76680
diff changeset
339 return self.hashvalue
f981fe3b8bf7 Move make_key() out of the decorator body. Make keys that only need to be hashed once.
Raymond Hettinger <python@rcn.com>
parents: 76680
diff changeset
340
87690
66c1c9f32567 Add use_weakref option to functools.lru_cache
Radomir Dopieralski <devel@sheep.art.pl>
parents: 86921
diff changeset
341 def _weaken(arg, callback=None):
66c1c9f32567 Add use_weakref option to functools.lru_cache
Radomir Dopieralski <devel@sheep.art.pl>
parents: 86921
diff changeset
342 """Try to make weak reference. Return the original object if it fails."""
66c1c9f32567 Add use_weakref option to functools.lru_cache
Radomir Dopieralski <devel@sheep.art.pl>
parents: 86921
diff changeset
343 try:
66c1c9f32567 Add use_weakref option to functools.lru_cache
Radomir Dopieralski <devel@sheep.art.pl>
parents: 86921
diff changeset
344 return weakref.ref(arg, callback)
66c1c9f32567 Add use_weakref option to functools.lru_cache
Radomir Dopieralski <devel@sheep.art.pl>
parents: 86921
diff changeset
345 except TypeError:
66c1c9f32567 Add use_weakref option to functools.lru_cache
Radomir Dopieralski <devel@sheep.art.pl>
parents: 86921
diff changeset
346 return arg
66c1c9f32567 Add use_weakref option to functools.lru_cache
Radomir Dopieralski <devel@sheep.art.pl>
parents: 86921
diff changeset
347
66c1c9f32567 Add use_weakref option to functools.lru_cache
Radomir Dopieralski <devel@sheep.art.pl>
parents: 86921
diff changeset
348 def _make_key(args, kwds, typed, remove_key=None,
77336
2d5ca0ea2aab Separate key creation logic from the sequence class that memoizes its hash value.
Raymond Hettinger <python@rcn.com>
parents: 77068
diff changeset
349 kwd_mark = (object(),),
2d5ca0ea2aab Separate key creation logic from the sequence class that memoizes its hash value.
Raymond Hettinger <python@rcn.com>
parents: 77068
diff changeset
350 fasttypes = {int, str, frozenset, type(None)},
2d5ca0ea2aab Separate key creation logic from the sequence class that memoizes its hash value.
Raymond Hettinger <python@rcn.com>
parents: 77068
diff changeset
351 sorted=sorted, tuple=tuple, type=type, len=len):
82558
1af9f7df3a96 Improve comments and variable names.
Raymond Hettinger <python@rcn.com>
parents: 82470
diff changeset
352 """Make a cache key from optionally typed positional and keyword arguments
1af9f7df3a96 Improve comments and variable names.
Raymond Hettinger <python@rcn.com>
parents: 82470
diff changeset
353
1af9f7df3a96 Improve comments and variable names.
Raymond Hettinger <python@rcn.com>
parents: 82470
diff changeset
354 The key is constructed in a way that is flat as possible rather than
1af9f7df3a96 Improve comments and variable names.
Raymond Hettinger <python@rcn.com>
parents: 82470
diff changeset
355 as a nested structure that would take more memory.
1af9f7df3a96 Improve comments and variable names.
Raymond Hettinger <python@rcn.com>
parents: 82470
diff changeset
356
1af9f7df3a96 Improve comments and variable names.
Raymond Hettinger <python@rcn.com>
parents: 82470
diff changeset
357 If there is only a single argument and its data type is known to cache
1af9f7df3a96 Improve comments and variable names.
Raymond Hettinger <python@rcn.com>
parents: 82470
diff changeset
358 its hash value, then that argument is returned without a wrapper. This
1af9f7df3a96 Improve comments and variable names.
Raymond Hettinger <python@rcn.com>
parents: 82470
diff changeset
359 saves space and improves lookup speed.
1af9f7df3a96 Improve comments and variable names.
Raymond Hettinger <python@rcn.com>
parents: 82470
diff changeset
360
1af9f7df3a96 Improve comments and variable names.
Raymond Hettinger <python@rcn.com>
parents: 82470
diff changeset
361 """
77336
2d5ca0ea2aab Separate key creation logic from the sequence class that memoizes its hash value.
Raymond Hettinger <python@rcn.com>
parents: 77068
diff changeset
362 key = args
2d5ca0ea2aab Separate key creation logic from the sequence class that memoizes its hash value.
Raymond Hettinger <python@rcn.com>
parents: 77068
diff changeset
363 if kwds:
2d5ca0ea2aab Separate key creation logic from the sequence class that memoizes its hash value.
Raymond Hettinger <python@rcn.com>
parents: 77068
diff changeset
364 sorted_items = sorted(kwds.items())
2d5ca0ea2aab Separate key creation logic from the sequence class that memoizes its hash value.
Raymond Hettinger <python@rcn.com>
parents: 77068
diff changeset
365 key += kwd_mark
2d5ca0ea2aab Separate key creation logic from the sequence class that memoizes its hash value.
Raymond Hettinger <python@rcn.com>
parents: 77068
diff changeset
366 for item in sorted_items:
2d5ca0ea2aab Separate key creation logic from the sequence class that memoizes its hash value.
Raymond Hettinger <python@rcn.com>
parents: 77068
diff changeset
367 key += item
2d5ca0ea2aab Separate key creation logic from the sequence class that memoizes its hash value.
Raymond Hettinger <python@rcn.com>
parents: 77068
diff changeset
368 if typed:
2d5ca0ea2aab Separate key creation logic from the sequence class that memoizes its hash value.
Raymond Hettinger <python@rcn.com>
parents: 77068
diff changeset
369 key += tuple(type(v) for v in args)
2d5ca0ea2aab Separate key creation logic from the sequence class that memoizes its hash value.
Raymond Hettinger <python@rcn.com>
parents: 77068
diff changeset
370 if kwds:
2d5ca0ea2aab Separate key creation logic from the sequence class that memoizes its hash value.
Raymond Hettinger <python@rcn.com>
parents: 77068
diff changeset
371 key += tuple(type(v) for k, v in sorted_items)
2d5ca0ea2aab Separate key creation logic from the sequence class that memoizes its hash value.
Raymond Hettinger <python@rcn.com>
parents: 77068
diff changeset
372 elif len(key) == 1 and type(key[0]) in fasttypes:
2d5ca0ea2aab Separate key creation logic from the sequence class that memoizes its hash value.
Raymond Hettinger <python@rcn.com>
parents: 77068
diff changeset
373 return key[0]
2d5ca0ea2aab Separate key creation logic from the sequence class that memoizes its hash value.
Raymond Hettinger <python@rcn.com>
parents: 77068
diff changeset
374 return _HashedSeq(key)
2d5ca0ea2aab Separate key creation logic from the sequence class that memoizes its hash value.
Raymond Hettinger <python@rcn.com>
parents: 77068
diff changeset
375
87690
66c1c9f32567 Add use_weakref option to functools.lru_cache
Radomir Dopieralski <devel@sheep.art.pl>
parents: 86921
diff changeset
376 def _make_weakref_key(args, kwds, typed, remove_key,
66c1c9f32567 Add use_weakref option to functools.lru_cache
Radomir Dopieralski <devel@sheep.art.pl>
parents: 86921
diff changeset
377 kwd_mark = (object(),),
66c1c9f32567 Add use_weakref option to functools.lru_cache
Radomir Dopieralski <devel@sheep.art.pl>
parents: 86921
diff changeset
378 fasttypes= {int, str, frozenset, type(None)},
66c1c9f32567 Add use_weakref option to functools.lru_cache
Radomir Dopieralski <devel@sheep.art.pl>
parents: 86921
diff changeset
379 sorted=sorted, tuple=tuple, type=type, len=len):
66c1c9f32567 Add use_weakref option to functools.lru_cache
Radomir Dopieralski <devel@sheep.art.pl>
parents: 86921
diff changeset
380 """Like ``_make_key``, but use weak references to arguments.
66c1c9f32567 Add use_weakref option to functools.lru_cache
Radomir Dopieralski <devel@sheep.art.pl>
parents: 86921
diff changeset
381
66c1c9f32567 Add use_weakref option to functools.lru_cache
Radomir Dopieralski <devel@sheep.art.pl>
parents: 86921
diff changeset
382 The function ``remove_key`` will be called back with a key when any of that
66c1c9f32567 Add use_weakref option to functools.lru_cache
Radomir Dopieralski <devel@sheep.art.pl>
parents: 86921
diff changeset
383 key's arguments no longer has any references.
66c1c9f32567 Add use_weakref option to functools.lru_cache
Radomir Dopieralski <devel@sheep.art.pl>
parents: 86921
diff changeset
384
66c1c9f32567 Add use_weakref option to functools.lru_cache
Radomir Dopieralski <devel@sheep.art.pl>
parents: 86921
diff changeset
385 This function duplicates some code from ``_make_key`` for performance
66c1c9f32567 Add use_weakref option to functools.lru_cache
Radomir Dopieralski <devel@sheep.art.pl>
parents: 86921
diff changeset
386 reasons, to avoid additional checks and function calls in the original
66c1c9f32567 Add use_weakref option to functools.lru_cache
Radomir Dopieralski <devel@sheep.art.pl>
parents: 86921
diff changeset
387 function.
66c1c9f32567 Add use_weakref option to functools.lru_cache
Radomir Dopieralski <devel@sheep.art.pl>
parents: 86921
diff changeset
388 """
66c1c9f32567 Add use_weakref option to functools.lru_cache
Radomir Dopieralski <devel@sheep.art.pl>
parents: 86921
diff changeset
389 key = None
66c1c9f32567 Add use_weakref option to functools.lru_cache
Radomir Dopieralski <devel@sheep.art.pl>
parents: 86921
diff changeset
390
66c1c9f32567 Add use_weakref option to functools.lru_cache
Radomir Dopieralski <devel@sheep.art.pl>
parents: 86921
diff changeset
391 def weakref_callback(ref):
66c1c9f32567 Add use_weakref option to functools.lru_cache
Radomir Dopieralski <devel@sheep.art.pl>
parents: 86921
diff changeset
392 # The key here is stored in a closure, because we need this callback
66c1c9f32567 Add use_weakref option to functools.lru_cache
Radomir Dopieralski <devel@sheep.art.pl>
parents: 86921
diff changeset
393 # before we have the key, as it is used in the weakrefs for the key.
66c1c9f32567 Add use_weakref option to functools.lru_cache
Radomir Dopieralski <devel@sheep.art.pl>
parents: 86921
diff changeset
394 remove_key(key)
66c1c9f32567 Add use_weakref option to functools.lru_cache
Radomir Dopieralski <devel@sheep.art.pl>
parents: 86921
diff changeset
395
66c1c9f32567 Add use_weakref option to functools.lru_cache
Radomir Dopieralski <devel@sheep.art.pl>
parents: 86921
diff changeset
396 key = tuple(_weaken(arg, weakref_callback) for arg in args)
66c1c9f32567 Add use_weakref option to functools.lru_cache
Radomir Dopieralski <devel@sheep.art.pl>
parents: 86921
diff changeset
397 if kwds:
66c1c9f32567 Add use_weakref option to functools.lru_cache
Radomir Dopieralski <devel@sheep.art.pl>
parents: 86921
diff changeset
398 sorted_items = sorted(kwds.items())
66c1c9f32567 Add use_weakref option to functools.lru_cache
Radomir Dopieralski <devel@sheep.art.pl>
parents: 86921
diff changeset
399 key += kwd_mark
66c1c9f32567 Add use_weakref option to functools.lru_cache
Radomir Dopieralski <devel@sheep.art.pl>
parents: 86921
diff changeset
400 for key, value in sorted_items:
66c1c9f32567 Add use_weakref option to functools.lru_cache
Radomir Dopieralski <devel@sheep.art.pl>
parents: 86921
diff changeset
401 key += key, _weaken(value, weakref_callback)
66c1c9f32567 Add use_weakref option to functools.lru_cache
Radomir Dopieralski <devel@sheep.art.pl>
parents: 86921
diff changeset
402 if typed:
66c1c9f32567 Add use_weakref option to functools.lru_cache
Radomir Dopieralski <devel@sheep.art.pl>
parents: 86921
diff changeset
403 key += tuple(type(v) for v in args)
66c1c9f32567 Add use_weakref option to functools.lru_cache
Radomir Dopieralski <devel@sheep.art.pl>
parents: 86921
diff changeset
404 if kwds:
66c1c9f32567 Add use_weakref option to functools.lru_cache
Radomir Dopieralski <devel@sheep.art.pl>
parents: 86921
diff changeset
405 key += tuple(type(v) for k, v in sorted_items)
66c1c9f32567 Add use_weakref option to functools.lru_cache
Radomir Dopieralski <devel@sheep.art.pl>
parents: 86921
diff changeset
406 elif len(key) == 1 and type(key[0]) in fasttypes:
66c1c9f32567 Add use_weakref option to functools.lru_cache
Radomir Dopieralski <devel@sheep.art.pl>
parents: 86921
diff changeset
407 return key[0]
66c1c9f32567 Add use_weakref option to functools.lru_cache
Radomir Dopieralski <devel@sheep.art.pl>
parents: 86921
diff changeset
408 return _HashedSeq(key)
66c1c9f32567 Add use_weakref option to functools.lru_cache
Radomir Dopieralski <devel@sheep.art.pl>
parents: 86921
diff changeset
409
66c1c9f32567 Add use_weakref option to functools.lru_cache
Radomir Dopieralski <devel@sheep.art.pl>
parents: 86921
diff changeset
410 def lru_cache(maxsize=128, typed=False, use_weakref=False):
63823
1086dad50c74 use same quoting as the rest of the file
Benjamin Peterson <benjamin@python.org>
parents: 63745
diff changeset
411 """Least-recently-used cache decorator.
63370
c55876a6fa3c Re-commit r83327 now that the release is done.
Georg Brandl <georg@python.org>
parents: 63357
diff changeset
412
66582
00c8cdf53936 Issue 10593: Adopt Nick's suggestion for an lru_cache with maxsize=None.
Raymond Hettinger <python@rcn.com>
parents: 66578
diff changeset
413 If *maxsize* is set to None, the LRU features are disabled and the cache
00c8cdf53936 Issue 10593: Adopt Nick's suggestion for an lru_cache with maxsize=None.
Raymond Hettinger <python@rcn.com>
parents: 66578
diff changeset
414 can grow without bound.
00c8cdf53936 Issue 10593: Adopt Nick's suggestion for an lru_cache with maxsize=None.
Raymond Hettinger <python@rcn.com>
parents: 66578
diff changeset
415
73019
cba503a2c468 Issue 13227: Option to make the lru_cache() type specific (suggested by Andrew Koenig).
Raymond Hettinger <python@rcn.com>
parents: 72944
diff changeset
416 If *typed* is True, arguments of different types will be cached separately.
cba503a2c468 Issue 13227: Option to make the lru_cache() type specific (suggested by Andrew Koenig).
Raymond Hettinger <python@rcn.com>
parents: 72944
diff changeset
417 For example, f(3.0) and f(3) will be treated as distinct calls with
cba503a2c468 Issue 13227: Option to make the lru_cache() type specific (suggested by Andrew Koenig).
Raymond Hettinger <python@rcn.com>
parents: 72944
diff changeset
418 distinct results.
cba503a2c468 Issue 13227: Option to make the lru_cache() type specific (suggested by Andrew Koenig).
Raymond Hettinger <python@rcn.com>
parents: 72944
diff changeset
419
87690
66c1c9f32567 Add use_weakref option to functools.lru_cache
Radomir Dopieralski <devel@sheep.art.pl>
parents: 86921
diff changeset
420 If *use_weakref* is True, the cache will not keep references to the
66c1c9f32567 Add use_weakref option to functools.lru_cache
Radomir Dopieralski <devel@sheep.art.pl>
parents: 86921
diff changeset
421 arguments, keeping them alive in memory forever. Instead, cache entries
66c1c9f32567 Add use_weakref option to functools.lru_cache
Radomir Dopieralski <devel@sheep.art.pl>
parents: 86921
diff changeset
422 related to objects that are no longer used will be automatically removed
66c1c9f32567 Add use_weakref option to functools.lru_cache
Radomir Dopieralski <devel@sheep.art.pl>
parents: 86921
diff changeset
423 from cache.
66c1c9f32567 Add use_weakref option to functools.lru_cache
Radomir Dopieralski <devel@sheep.art.pl>
parents: 86921
diff changeset
424
63370
c55876a6fa3c Re-commit r83327 now that the release is done.
Georg Brandl <georg@python.org>
parents: 63357
diff changeset
425 Arguments to the cached function must be hashable.
66441
03d933948bf3 Clean-up docstring, comments, and whitespace.
Raymond Hettinger <python@rcn.com>
parents: 64776
diff changeset
426
76003
387dcd8d7dec Fix-up comments and add a sentinel variable for clarity.
Raymond Hettinger <python@rcn.com>
parents: 76002
diff changeset
427 View the cache statistics named tuple (hits, misses, maxsize, currsize)
387dcd8d7dec Fix-up comments and add a sentinel variable for clarity.
Raymond Hettinger <python@rcn.com>
parents: 76002
diff changeset
428 with f.cache_info(). Clear the cache and statistics with f.cache_clear().
66578
5cb53f094c1a Doc and docstring nits.
Raymond Hettinger <python@rcn.com>
parents: 66573
diff changeset
429 Access the underlying function with f.__wrapped__.
66441
03d933948bf3 Clean-up docstring, comments, and whitespace.
Raymond Hettinger <python@rcn.com>
parents: 64776
diff changeset
430
03d933948bf3 Clean-up docstring, comments, and whitespace.
Raymond Hettinger <python@rcn.com>
parents: 64776
diff changeset
431 See: http://en.wikipedia.org/wiki/Cache_algorithms#Least_Recently_Used
63370
c55876a6fa3c Re-commit r83327 now that the release is done.
Georg Brandl <georg@python.org>
parents: 63357
diff changeset
432
63823
1086dad50c74 use same quoting as the rest of the file
Benjamin Peterson <benjamin@python.org>
parents: 63745
diff changeset
433 """
75998
123cf2192c79 Minor cleanup: add whitespace, add comments, bring function attribute updates together.
Raymond Hettinger <python@rcn.com>
parents: 75803
diff changeset
434
66441
03d933948bf3 Clean-up docstring, comments, and whitespace.
Raymond Hettinger <python@rcn.com>
parents: 64776
diff changeset
435 # Users should only access the lru_cache through its public API:
66552
f16bf4cae5d7 Neaten-up a bit.
Raymond Hettinger <python@rcn.com>
parents: 66550
diff changeset
436 # cache_info, cache_clear, and f.__wrapped__
66441
03d933948bf3 Clean-up docstring, comments, and whitespace.
Raymond Hettinger <python@rcn.com>
parents: 64776
diff changeset
437 # The internals of the lru_cache are encapsulated for thread safety and
03d933948bf3 Clean-up docstring, comments, and whitespace.
Raymond Hettinger <python@rcn.com>
parents: 64776
diff changeset
438 # to allow the implementation to change (including a possible C version).
03d933948bf3 Clean-up docstring, comments, and whitespace.
Raymond Hettinger <python@rcn.com>
parents: 64776
diff changeset
439
76649
2adcd28a5a3a Factor out shared variables.
Raymond Hettinger <python@rcn.com>
parents: 76643
diff changeset
440 # Constants shared by all lru cache instances:
76656
d4fd58fff480 Track the cache size directly.
Raymond Hettinger <python@rcn.com>
parents: 76649
diff changeset
441 sentinel = object() # unique object used to signal cache misses
76649
2adcd28a5a3a Factor out shared variables.
Raymond Hettinger <python@rcn.com>
parents: 76643
diff changeset
442 PREV, NEXT, KEY, RESULT = 0, 1, 2, 3 # names for the link fields
2adcd28a5a3a Factor out shared variables.
Raymond Hettinger <python@rcn.com>
parents: 76643
diff changeset
443
87690
66c1c9f32567 Add use_weakref option to functools.lru_cache
Radomir Dopieralski <devel@sheep.art.pl>
parents: 86921
diff changeset
444 if use_weakref:
66c1c9f32567 Add use_weakref option to functools.lru_cache
Radomir Dopieralski <devel@sheep.art.pl>
parents: 86921
diff changeset
445 make_key = _make_weakref_key
66c1c9f32567 Add use_weakref option to functools.lru_cache
Radomir Dopieralski <devel@sheep.art.pl>
parents: 86921
diff changeset
446 else:
66c1c9f32567 Add use_weakref option to functools.lru_cache
Radomir Dopieralski <devel@sheep.art.pl>
parents: 86921
diff changeset
447 make_key = _make_key # build a key from the function arguments
66c1c9f32567 Add use_weakref option to functools.lru_cache
Radomir Dopieralski <devel@sheep.art.pl>
parents: 86921
diff changeset
448
75757
51b0711ee672 Refactor calculation of the cache key. Minor code cleanups.
Raymond Hettinger <python@rcn.com>
parents: 75753
diff changeset
449 def decorating_function(user_function):
76003
387dcd8d7dec Fix-up comments and add a sentinel variable for clarity.
Raymond Hettinger <python@rcn.com>
parents: 76002
diff changeset
450 cache = {}
82560
a9fa8a18d18d Sync-up with 3.4 to make maintenance easier.
Raymond Hettinger <python@rcn.com>
parents: 82558
diff changeset
451 hits = misses = 0
76680
f5bb290c751a Use a flag to indicate when the circular queue is fully populated and stable.
Raymond Hettinger <python@rcn.com>
parents: 76675
diff changeset
452 full = False
76004
1c22c1109824 Fix-up a comment
Raymond Hettinger <python@rcn.com>
parents: 76003
diff changeset
453 cache_get = cache.get # bound method to lookup a key or return None
82437
1920422626a5 Don't deadlock on a reentrant call.
Raymond Hettinger <python@rcn.com>
parents: 77336
diff changeset
454 lock = RLock() # because linkedlist updates aren't threadsafe
76003
387dcd8d7dec Fix-up comments and add a sentinel variable for clarity.
Raymond Hettinger <python@rcn.com>
parents: 76002
diff changeset
455 root = [] # root of the circular doubly linked list
387dcd8d7dec Fix-up comments and add a sentinel variable for clarity.
Raymond Hettinger <python@rcn.com>
parents: 76002
diff changeset
456 root[:] = [root, root, None, None] # initialize by pointing to self
87690
66c1c9f32567 Add use_weakref option to functools.lru_cache
Radomir Dopieralski <devel@sheep.art.pl>
parents: 86921
diff changeset
457 remove_key = None # only used with use_weakref
66c1c9f32567 Add use_weakref option to functools.lru_cache
Radomir Dopieralski <devel@sheep.art.pl>
parents: 86921
diff changeset
458
75757
51b0711ee672 Refactor calculation of the cache key. Minor code cleanups.
Raymond Hettinger <python@rcn.com>
parents: 75753
diff changeset
459
75802
7080f443bd37 Low overhead path for maxsize==0
Raymond Hettinger <python@rcn.com>
parents: 75776
diff changeset
460 if maxsize == 0:
7080f443bd37 Low overhead path for maxsize==0
Raymond Hettinger <python@rcn.com>
parents: 75776
diff changeset
461
7080f443bd37 Low overhead path for maxsize==0
Raymond Hettinger <python@rcn.com>
parents: 75776
diff changeset
462 def wrapper(*args, **kwds):
82558
1af9f7df3a96 Improve comments and variable names.
Raymond Hettinger <python@rcn.com>
parents: 82470
diff changeset
463 # No caching -- just a statistics update after a successful call
75802
7080f443bd37 Low overhead path for maxsize==0
Raymond Hettinger <python@rcn.com>
parents: 75776
diff changeset
464 nonlocal misses
75803
b26056192653 Fix whitespace
Raymond Hettinger <python@rcn.com>
parents: 75802
diff changeset
465 result = user_function(*args, **kwds)
75802
7080f443bd37 Low overhead path for maxsize==0
Raymond Hettinger <python@rcn.com>
parents: 75776
diff changeset
466 misses += 1
7080f443bd37 Low overhead path for maxsize==0
Raymond Hettinger <python@rcn.com>
parents: 75776
diff changeset
467 return result
7080f443bd37 Low overhead path for maxsize==0
Raymond Hettinger <python@rcn.com>
parents: 75776
diff changeset
468
7080f443bd37 Low overhead path for maxsize==0
Raymond Hettinger <python@rcn.com>
parents: 75776
diff changeset
469 elif maxsize is None:
87690
66c1c9f32567 Add use_weakref option to functools.lru_cache
Radomir Dopieralski <devel@sheep.art.pl>
parents: 86921
diff changeset
470 if use_weakref:
66c1c9f32567 Add use_weakref option to functools.lru_cache
Radomir Dopieralski <devel@sheep.art.pl>
parents: 86921
diff changeset
471
66c1c9f32567 Add use_weakref option to functools.lru_cache
Radomir Dopieralski <devel@sheep.art.pl>
parents: 86921
diff changeset
472 def remove_key(key):
66c1c9f32567 Add use_weakref option to functools.lru_cache
Radomir Dopieralski <devel@sheep.art.pl>
parents: 86921
diff changeset
473 # A callback for removing keys from cache
66c1c9f32567 Add use_weakref option to functools.lru_cache
Radomir Dopieralski <devel@sheep.art.pl>
parents: 86921
diff changeset
474 try:
66c1c9f32567 Add use_weakref option to functools.lru_cache
Radomir Dopieralski <devel@sheep.art.pl>
parents: 86921
diff changeset
475 del cache[key]
66c1c9f32567 Add use_weakref option to functools.lru_cache
Radomir Dopieralski <devel@sheep.art.pl>
parents: 86921
diff changeset
476 except KeyError:
66c1c9f32567 Add use_weakref option to functools.lru_cache
Radomir Dopieralski <devel@sheep.art.pl>
parents: 86921
diff changeset
477 pass
75776
66803fd0a6bc Section-off the source for better readability.
Raymond Hettinger <python@rcn.com>
parents: 75775
diff changeset
478
66582
00c8cdf53936 Issue 10593: Adopt Nick's suggestion for an lru_cache with maxsize=None.
Raymond Hettinger <python@rcn.com>
parents: 66578
diff changeset
479 def wrapper(*args, **kwds):
82558
1af9f7df3a96 Improve comments and variable names.
Raymond Hettinger <python@rcn.com>
parents: 82470
diff changeset
480 # Simple caching without ordering or size limit
82560
a9fa8a18d18d Sync-up with 3.4 to make maintenance easier.
Raymond Hettinger <python@rcn.com>
parents: 82558
diff changeset
481 nonlocal hits, misses
87690
66c1c9f32567 Add use_weakref option to functools.lru_cache
Radomir Dopieralski <devel@sheep.art.pl>
parents: 86921
diff changeset
482 key = make_key(args, kwds, typed, remove_key)
76003
387dcd8d7dec Fix-up comments and add a sentinel variable for clarity.
Raymond Hettinger <python@rcn.com>
parents: 76002
diff changeset
483 result = cache_get(key, sentinel)
387dcd8d7dec Fix-up comments and add a sentinel variable for clarity.
Raymond Hettinger <python@rcn.com>
parents: 76002
diff changeset
484 if result is not sentinel:
66550
312b2916cfd4 Issue 10586: change the new functools.lru_cache implementation to expose the maximum and current cache sizes through the public statistics API. This API is now a single function that returns a named tuple.
Nick Coghlan <ncoghlan@gmail.com>
parents: 66441
diff changeset
485 hits += 1
72943
8365f82f8a13 Issue 13177: Make tracebacks more readable by avoiding chained exceptions in the lru_cache.
Raymond Hettinger <python@rcn.com>
parents: 69862
diff changeset
486 return result
8365f82f8a13 Issue 13177: Make tracebacks more readable by avoiding chained exceptions in the lru_cache.
Raymond Hettinger <python@rcn.com>
parents: 69862
diff changeset
487 result = user_function(*args, **kwds)
8365f82f8a13 Issue 13177: Make tracebacks more readable by avoiding chained exceptions in the lru_cache.
Raymond Hettinger <python@rcn.com>
parents: 69862
diff changeset
488 cache[key] = result
8365f82f8a13 Issue 13177: Make tracebacks more readable by avoiding chained exceptions in the lru_cache.
Raymond Hettinger <python@rcn.com>
parents: 69862
diff changeset
489 misses += 1
66582
00c8cdf53936 Issue 10593: Adopt Nick's suggestion for an lru_cache with maxsize=None.
Raymond Hettinger <python@rcn.com>
parents: 66578
diff changeset
490 return result
75776
66803fd0a6bc Section-off the source for better readability.
Raymond Hettinger <python@rcn.com>
parents: 75775
diff changeset
491
66582
00c8cdf53936 Issue 10593: Adopt Nick's suggestion for an lru_cache with maxsize=None.
Raymond Hettinger <python@rcn.com>
parents: 66578
diff changeset
492 else:
87690
66c1c9f32567 Add use_weakref option to functools.lru_cache
Radomir Dopieralski <devel@sheep.art.pl>
parents: 86921
diff changeset
493 if use_weakref:
66c1c9f32567 Add use_weakref option to functools.lru_cache
Radomir Dopieralski <devel@sheep.art.pl>
parents: 86921
diff changeset
494
66c1c9f32567 Add use_weakref option to functools.lru_cache
Radomir Dopieralski <devel@sheep.art.pl>
parents: 86921
diff changeset
495 def remove_key(key):
66c1c9f32567 Add use_weakref option to functools.lru_cache
Radomir Dopieralski <devel@sheep.art.pl>
parents: 86921
diff changeset
496 # A callback for removing keys from cache
66c1c9f32567 Add use_weakref option to functools.lru_cache
Radomir Dopieralski <devel@sheep.art.pl>
parents: 86921
diff changeset
497 with lock:
66c1c9f32567 Add use_weakref option to functools.lru_cache
Radomir Dopieralski <devel@sheep.art.pl>
parents: 86921
diff changeset
498 link = cache_get(key)
66c1c9f32567 Add use_weakref option to functools.lru_cache
Radomir Dopieralski <devel@sheep.art.pl>
parents: 86921
diff changeset
499 if link is not None:
66c1c9f32567 Add use_weakref option to functools.lru_cache
Radomir Dopieralski <devel@sheep.art.pl>
parents: 86921
diff changeset
500 link_prev, link_next, _key, result = link
66c1c9f32567 Add use_weakref option to functools.lru_cache
Radomir Dopieralski <devel@sheep.art.pl>
parents: 86921
diff changeset
501 link_prev[NEXT] = link_next
66c1c9f32567 Add use_weakref option to functools.lru_cache
Radomir Dopieralski <devel@sheep.art.pl>
parents: 86921
diff changeset
502 link_next[PREV] = link_prev
66c1c9f32567 Add use_weakref option to functools.lru_cache
Radomir Dopieralski <devel@sheep.art.pl>
parents: 86921
diff changeset
503 del cache[key]
75776
66803fd0a6bc Section-off the source for better readability.
Raymond Hettinger <python@rcn.com>
parents: 75775
diff changeset
504
66582
00c8cdf53936 Issue 10593: Adopt Nick's suggestion for an lru_cache with maxsize=None.
Raymond Hettinger <python@rcn.com>
parents: 66578
diff changeset
505 def wrapper(*args, **kwds):
82558
1af9f7df3a96 Improve comments and variable names.
Raymond Hettinger <python@rcn.com>
parents: 82470
diff changeset
506 # Size limited caching that tracks accesses by recency
82560
a9fa8a18d18d Sync-up with 3.4 to make maintenance easier.
Raymond Hettinger <python@rcn.com>
parents: 82558
diff changeset
507 nonlocal root, hits, misses, full
87690
66c1c9f32567 Add use_weakref option to functools.lru_cache
Radomir Dopieralski <devel@sheep.art.pl>
parents: 86921
diff changeset
508 key = make_key(args, kwds, typed, remove_key)
72943
8365f82f8a13 Issue 13177: Make tracebacks more readable by avoiding chained exceptions in the lru_cache.
Raymond Hettinger <python@rcn.com>
parents: 69862
diff changeset
509 with lock:
75729
3b2856d8614b Improve the memory utilization (and speed) of functools.lru_cache().
Raymond Hettinger <python@rcn.com>
parents: 73943
diff changeset
510 link = cache_get(key)
3b2856d8614b Improve the memory utilization (and speed) of functools.lru_cache().
Raymond Hettinger <python@rcn.com>
parents: 73943
diff changeset
511 if link is not None:
82558
1af9f7df3a96 Improve comments and variable names.
Raymond Hettinger <python@rcn.com>
parents: 82470
diff changeset
512 # Move the link to the front of the circular queue
1af9f7df3a96 Improve comments and variable names.
Raymond Hettinger <python@rcn.com>
parents: 82470
diff changeset
513 link_prev, link_next, _key, result = link
75729
3b2856d8614b Improve the memory utilization (and speed) of functools.lru_cache().
Raymond Hettinger <python@rcn.com>
parents: 73943
diff changeset
514 link_prev[NEXT] = link_next
3b2856d8614b Improve the memory utilization (and speed) of functools.lru_cache().
Raymond Hettinger <python@rcn.com>
parents: 73943
diff changeset
515 link_next[PREV] = link_prev
3b2856d8614b Improve the memory utilization (and speed) of functools.lru_cache().
Raymond Hettinger <python@rcn.com>
parents: 73943
diff changeset
516 last = root[PREV]
3b2856d8614b Improve the memory utilization (and speed) of functools.lru_cache().
Raymond Hettinger <python@rcn.com>
parents: 73943
diff changeset
517 last[NEXT] = root[PREV] = link
3b2856d8614b Improve the memory utilization (and speed) of functools.lru_cache().
Raymond Hettinger <python@rcn.com>
parents: 73943
diff changeset
518 link[PREV] = last
3b2856d8614b Improve the memory utilization (and speed) of functools.lru_cache().
Raymond Hettinger <python@rcn.com>
parents: 73943
diff changeset
519 link[NEXT] = root
66582
00c8cdf53936 Issue 10593: Adopt Nick's suggestion for an lru_cache with maxsize=None.
Raymond Hettinger <python@rcn.com>
parents: 66578
diff changeset
520 hits += 1
72943
8365f82f8a13 Issue 13177: Make tracebacks more readable by avoiding chained exceptions in the lru_cache.
Raymond Hettinger <python@rcn.com>
parents: 69862
diff changeset
521 return result
8365f82f8a13 Issue 13177: Make tracebacks more readable by avoiding chained exceptions in the lru_cache.
Raymond Hettinger <python@rcn.com>
parents: 69862
diff changeset
522 result = user_function(*args, **kwds)
8365f82f8a13 Issue 13177: Make tracebacks more readable by avoiding chained exceptions in the lru_cache.
Raymond Hettinger <python@rcn.com>
parents: 69862
diff changeset
523 with lock:
76675
b3aeaef6c315 Handle a possible race condition
Raymond Hettinger <python@rcn.com>
parents: 76656
diff changeset
524 if key in cache:
82558
1af9f7df3a96 Improve comments and variable names.
Raymond Hettinger <python@rcn.com>
parents: 82470
diff changeset
525 # Getting here means that this same key was added to the
1af9f7df3a96 Improve comments and variable names.
Raymond Hettinger <python@rcn.com>
parents: 82470
diff changeset
526 # cache while the lock was released. Since the link
76675
b3aeaef6c315 Handle a possible race condition
Raymond Hettinger <python@rcn.com>
parents: 76656
diff changeset
527 # update is already done, we need only return the
b3aeaef6c315 Handle a possible race condition
Raymond Hettinger <python@rcn.com>
parents: 76656
diff changeset
528 # computed result and update the count of misses.
b3aeaef6c315 Handle a possible race condition
Raymond Hettinger <python@rcn.com>
parents: 76656
diff changeset
529 pass
76680
f5bb290c751a Use a flag to indicate when the circular queue is fully populated and stable.
Raymond Hettinger <python@rcn.com>
parents: 76675
diff changeset
530 elif full:
82558
1af9f7df3a96 Improve comments and variable names.
Raymond Hettinger <python@rcn.com>
parents: 82470
diff changeset
531 # Use the old root to store the new key and result.
82468
4b06fd08b78c Fix other re-entrancy nits for the lru_cache.
Raymond Hettinger <python@rcn.com>
parents: 82450
diff changeset
532 oldroot = root
4b06fd08b78c Fix other re-entrancy nits for the lru_cache.
Raymond Hettinger <python@rcn.com>
parents: 82450
diff changeset
533 oldroot[KEY] = key
4b06fd08b78c Fix other re-entrancy nits for the lru_cache.
Raymond Hettinger <python@rcn.com>
parents: 82450
diff changeset
534 oldroot[RESULT] = result
82558
1af9f7df3a96 Improve comments and variable names.
Raymond Hettinger <python@rcn.com>
parents: 82470
diff changeset
535 # Empty the oldest link and make it the new root.
1af9f7df3a96 Improve comments and variable names.
Raymond Hettinger <python@rcn.com>
parents: 82470
diff changeset
536 # Keep a reference to the old key and old result to
1af9f7df3a96 Improve comments and variable names.
Raymond Hettinger <python@rcn.com>
parents: 82470
diff changeset
537 # prevent their ref counts from going to zero during the
1af9f7df3a96 Improve comments and variable names.
Raymond Hettinger <python@rcn.com>
parents: 82470
diff changeset
538 # update. That will prevent potentially arbitrary object
1af9f7df3a96 Improve comments and variable names.
Raymond Hettinger <python@rcn.com>
parents: 82470
diff changeset
539 # clean-up code (i.e. __del__) from running while we're
1af9f7df3a96 Improve comments and variable names.
Raymond Hettinger <python@rcn.com>
parents: 82470
diff changeset
540 # still adjusting the links.
82468
4b06fd08b78c Fix other re-entrancy nits for the lru_cache.
Raymond Hettinger <python@rcn.com>
parents: 82450
diff changeset
541 root = oldroot[NEXT]
4b06fd08b78c Fix other re-entrancy nits for the lru_cache.
Raymond Hettinger <python@rcn.com>
parents: 82450
diff changeset
542 oldkey = root[KEY]
82558
1af9f7df3a96 Improve comments and variable names.
Raymond Hettinger <python@rcn.com>
parents: 82470
diff changeset
543 oldresult = root[RESULT]
76004
1c22c1109824 Fix-up a comment
Raymond Hettinger <python@rcn.com>
parents: 76003
diff changeset
544 root[KEY] = root[RESULT] = None
82558
1af9f7df3a96 Improve comments and variable names.
Raymond Hettinger <python@rcn.com>
parents: 82470
diff changeset
545 # Now update the cache dictionary.
82468
4b06fd08b78c Fix other re-entrancy nits for the lru_cache.
Raymond Hettinger <python@rcn.com>
parents: 82450
diff changeset
546 del cache[oldkey]
82558
1af9f7df3a96 Improve comments and variable names.
Raymond Hettinger <python@rcn.com>
parents: 82470
diff changeset
547 # Save the potentially reentrant cache[key] assignment
1af9f7df3a96 Improve comments and variable names.
Raymond Hettinger <python@rcn.com>
parents: 82470
diff changeset
548 # for last, after the root and links have been put in
1af9f7df3a96 Improve comments and variable names.
Raymond Hettinger <python@rcn.com>
parents: 82470
diff changeset
549 # a consistent state.
82468
4b06fd08b78c Fix other re-entrancy nits for the lru_cache.
Raymond Hettinger <python@rcn.com>
parents: 82450
diff changeset
550 cache[key] = oldroot
76680
f5bb290c751a Use a flag to indicate when the circular queue is fully populated and stable.
Raymond Hettinger <python@rcn.com>
parents: 76675
diff changeset
551 else:
82558
1af9f7df3a96 Improve comments and variable names.
Raymond Hettinger <python@rcn.com>
parents: 82470
diff changeset
552 # Put result in a new link at the front of the queue.
76680
f5bb290c751a Use a flag to indicate when the circular queue is fully populated and stable.
Raymond Hettinger <python@rcn.com>
parents: 76675
diff changeset
553 last = root[PREV]
f5bb290c751a Use a flag to indicate when the circular queue is fully populated and stable.
Raymond Hettinger <python@rcn.com>
parents: 76675
diff changeset
554 link = [last, root, key, result]
82468
4b06fd08b78c Fix other re-entrancy nits for the lru_cache.
Raymond Hettinger <python@rcn.com>
parents: 82450
diff changeset
555 last[NEXT] = root[PREV] = cache[key] = link
82560
a9fa8a18d18d Sync-up with 3.4 to make maintenance easier.
Raymond Hettinger <python@rcn.com>
parents: 82558
diff changeset
556 full = (len(cache) >= maxsize)
72943
8365f82f8a13 Issue 13177: Make tracebacks more readable by avoiding chained exceptions in the lru_cache.
Raymond Hettinger <python@rcn.com>
parents: 69862
diff changeset
557 misses += 1
66582
00c8cdf53936 Issue 10593: Adopt Nick's suggestion for an lru_cache with maxsize=None.
Raymond Hettinger <python@rcn.com>
parents: 66578
diff changeset
558 return result
63370
c55876a6fa3c Re-commit r83327 now that the release is done.
Georg Brandl <georg@python.org>
parents: 63357
diff changeset
559
66550
312b2916cfd4 Issue 10586: change the new functools.lru_cache implementation to expose the maximum and current cache sizes through the public statistics API. This API is now a single function that returns a named tuple.
Nick Coghlan <ncoghlan@gmail.com>
parents: 66441
diff changeset
560 def cache_info():
66552
f16bf4cae5d7 Neaten-up a bit.
Raymond Hettinger <python@rcn.com>
parents: 66550
diff changeset
561 """Report cache statistics"""
66550
312b2916cfd4 Issue 10586: change the new functools.lru_cache implementation to expose the maximum and current cache sizes through the public statistics API. This API is now a single function that returns a named tuple.
Nick Coghlan <ncoghlan@gmail.com>
parents: 66441
diff changeset
562 with lock:
82560
a9fa8a18d18d Sync-up with 3.4 to make maintenance easier.
Raymond Hettinger <python@rcn.com>
parents: 82558
diff changeset
563 return _CacheInfo(hits, misses, maxsize, len(cache))
66550
312b2916cfd4 Issue 10586: change the new functools.lru_cache implementation to expose the maximum and current cache sizes through the public statistics API. This API is now a single function that returns a named tuple.
Nick Coghlan <ncoghlan@gmail.com>
parents: 66441
diff changeset
564
64448
61c44793238d Adopt more descriptive attribute names as suggested on python-dev.
Raymond Hettinger <python@rcn.com>
parents: 64382
diff changeset
565 def cache_clear():
63823
1086dad50c74 use same quoting as the rest of the file
Benjamin Peterson <benjamin@python.org>
parents: 63745
diff changeset
566 """Clear the cache and cache statistics"""
82560
a9fa8a18d18d Sync-up with 3.4 to make maintenance easier.
Raymond Hettinger <python@rcn.com>
parents: 82558
diff changeset
567 nonlocal hits, misses, full
64016
d8d0abe61e83 Add locks to make the caches well behaved in multi-threaded code.
Raymond Hettinger <python@rcn.com>
parents: 63823
diff changeset
568 with lock:
d8d0abe61e83 Add locks to make the caches well behaved in multi-threaded code.
Raymond Hettinger <python@rcn.com>
parents: 63823
diff changeset
569 cache.clear()
75752
087da2a353e6 clear the root with the cache
Benjamin Peterson <benjamin@python.org>
parents: 75749
diff changeset
570 root[:] = [root, root, None, None]
82560
a9fa8a18d18d Sync-up with 3.4 to make maintenance easier.
Raymond Hettinger <python@rcn.com>
parents: 82558
diff changeset
571 hits = misses = 0
76680
f5bb290c751a Use a flag to indicate when the circular queue is fully populated and stable.
Raymond Hettinger <python@rcn.com>
parents: 76675
diff changeset
572 full = False
63370
c55876a6fa3c Re-commit r83327 now that the release is done.
Georg Brandl <georg@python.org>
parents: 63357
diff changeset
573
66550
312b2916cfd4 Issue 10586: change the new functools.lru_cache implementation to expose the maximum and current cache sizes through the public statistics API. This API is now a single function that returns a named tuple.
Nick Coghlan <ncoghlan@gmail.com>
parents: 66441
diff changeset
574 wrapper.cache_info = cache_info
64448
61c44793238d Adopt more descriptive attribute names as suggested on python-dev.
Raymond Hettinger <python@rcn.com>
parents: 64382
diff changeset
575 wrapper.cache_clear = cache_clear
75998
123cf2192c79 Minor cleanup: add whitespace, add comments, bring function attribute updates together.
Raymond Hettinger <python@rcn.com>
parents: 75803
diff changeset
576 return update_wrapper(wrapper, user_function)
66441
03d933948bf3 Clean-up docstring, comments, and whitespace.
Raymond Hettinger <python@rcn.com>
parents: 64776
diff changeset
577
63370
c55876a6fa3c Re-commit r83327 now that the release is done.
Georg Brandl <georg@python.org>
parents: 63357
diff changeset
578 return decorating_function
84039
dfcb64f51f7b Add reference implementation for PEP 443
Łukasz Langa <lukasz@langa.pl>
parents: 82561
diff changeset
579
dfcb64f51f7b Add reference implementation for PEP 443
Łukasz Langa <lukasz@langa.pl>
parents: 82561
diff changeset
580
dfcb64f51f7b Add reference implementation for PEP 443
Łukasz Langa <lukasz@langa.pl>
parents: 82561
diff changeset
581 ################################################################################
dfcb64f51f7b Add reference implementation for PEP 443
Łukasz Langa <lukasz@langa.pl>
parents: 82561
diff changeset
582 ### singledispatch() - single-dispatch generic function decorator
dfcb64f51f7b Add reference implementation for PEP 443
Łukasz Langa <lukasz@langa.pl>
parents: 82561
diff changeset
583 ################################################################################
dfcb64f51f7b Add reference implementation for PEP 443
Łukasz Langa <lukasz@langa.pl>
parents: 82561
diff changeset
584
84411
a2672dc7c805 Issue #18244: Adopt C3-based linearization in functools.singledispatch for improved ABC support
Łukasz Langa <lukasz@langa.pl>
parents: 84114
diff changeset
585 def _c3_merge(sequences):
a2672dc7c805 Issue #18244: Adopt C3-based linearization in functools.singledispatch for improved ABC support
Łukasz Langa <lukasz@langa.pl>
parents: 84114
diff changeset
586 """Merges MROs in *sequences* to a single MRO using the C3 algorithm.
a2672dc7c805 Issue #18244: Adopt C3-based linearization in functools.singledispatch for improved ABC support
Łukasz Langa <lukasz@langa.pl>
parents: 84114
diff changeset
587
a2672dc7c805 Issue #18244: Adopt C3-based linearization in functools.singledispatch for improved ABC support
Łukasz Langa <lukasz@langa.pl>
parents: 84114
diff changeset
588 Adapted from http://www.python.org/download/releases/2.3/mro/.
a2672dc7c805 Issue #18244: Adopt C3-based linearization in functools.singledispatch for improved ABC support
Łukasz Langa <lukasz@langa.pl>
parents: 84114
diff changeset
589
a2672dc7c805 Issue #18244: Adopt C3-based linearization in functools.singledispatch for improved ABC support
Łukasz Langa <lukasz@langa.pl>
parents: 84114
diff changeset
590 """
a2672dc7c805 Issue #18244: Adopt C3-based linearization in functools.singledispatch for improved ABC support
Łukasz Langa <lukasz@langa.pl>
parents: 84114
diff changeset
591 result = []
a2672dc7c805 Issue #18244: Adopt C3-based linearization in functools.singledispatch for improved ABC support
Łukasz Langa <lukasz@langa.pl>
parents: 84114
diff changeset
592 while True:
a2672dc7c805 Issue #18244: Adopt C3-based linearization in functools.singledispatch for improved ABC support
Łukasz Langa <lukasz@langa.pl>
parents: 84114
diff changeset
593 sequences = [s for s in sequences if s] # purge empty sequences
a2672dc7c805 Issue #18244: Adopt C3-based linearization in functools.singledispatch for improved ABC support
Łukasz Langa <lukasz@langa.pl>
parents: 84114
diff changeset
594 if not sequences:
a2672dc7c805 Issue #18244: Adopt C3-based linearization in functools.singledispatch for improved ABC support
Łukasz Langa <lukasz@langa.pl>
parents: 84114
diff changeset
595 return result
a2672dc7c805 Issue #18244: Adopt C3-based linearization in functools.singledispatch for improved ABC support
Łukasz Langa <lukasz@langa.pl>
parents: 84114
diff changeset
596 for s1 in sequences: # find merge candidates among seq heads
a2672dc7c805 Issue #18244: Adopt C3-based linearization in functools.singledispatch for improved ABC support
Łukasz Langa <lukasz@langa.pl>
parents: 84114
diff changeset
597 candidate = s1[0]
a2672dc7c805 Issue #18244: Adopt C3-based linearization in functools.singledispatch for improved ABC support
Łukasz Langa <lukasz@langa.pl>
parents: 84114
diff changeset
598 for s2 in sequences:
a2672dc7c805 Issue #18244: Adopt C3-based linearization in functools.singledispatch for improved ABC support
Łukasz Langa <lukasz@langa.pl>
parents: 84114
diff changeset
599 if candidate in s2[1:]:
a2672dc7c805 Issue #18244: Adopt C3-based linearization in functools.singledispatch for improved ABC support
Łukasz Langa <lukasz@langa.pl>
parents: 84114
diff changeset
600 candidate = None
a2672dc7c805 Issue #18244: Adopt C3-based linearization in functools.singledispatch for improved ABC support
Łukasz Langa <lukasz@langa.pl>
parents: 84114
diff changeset
601 break # reject the current head, it appears later
a2672dc7c805 Issue #18244: Adopt C3-based linearization in functools.singledispatch for improved ABC support
Łukasz Langa <lukasz@langa.pl>
parents: 84114
diff changeset
602 else:
a2672dc7c805 Issue #18244: Adopt C3-based linearization in functools.singledispatch for improved ABC support
Łukasz Langa <lukasz@langa.pl>
parents: 84114
diff changeset
603 break
a2672dc7c805 Issue #18244: Adopt C3-based linearization in functools.singledispatch for improved ABC support
Łukasz Langa <lukasz@langa.pl>
parents: 84114
diff changeset
604 if not candidate:
a2672dc7c805 Issue #18244: Adopt C3-based linearization in functools.singledispatch for improved ABC support
Łukasz Langa <lukasz@langa.pl>
parents: 84114
diff changeset
605 raise RuntimeError("Inconsistent hierarchy")
a2672dc7c805 Issue #18244: Adopt C3-based linearization in functools.singledispatch for improved ABC support
Łukasz Langa <lukasz@langa.pl>
parents: 84114
diff changeset
606 result.append(candidate)
a2672dc7c805 Issue #18244: Adopt C3-based linearization in functools.singledispatch for improved ABC support
Łukasz Langa <lukasz@langa.pl>
parents: 84114
diff changeset
607 # remove the chosen candidate
a2672dc7c805 Issue #18244: Adopt C3-based linearization in functools.singledispatch for improved ABC support
Łukasz Langa <lukasz@langa.pl>
parents: 84114
diff changeset
608 for seq in sequences:
a2672dc7c805 Issue #18244: Adopt C3-based linearization in functools.singledispatch for improved ABC support
Łukasz Langa <lukasz@langa.pl>
parents: 84114
diff changeset
609 if seq[0] == candidate:
a2672dc7c805 Issue #18244: Adopt C3-based linearization in functools.singledispatch for improved ABC support
Łukasz Langa <lukasz@langa.pl>
parents: 84114
diff changeset
610 del seq[0]
a2672dc7c805 Issue #18244: Adopt C3-based linearization in functools.singledispatch for improved ABC support
Łukasz Langa <lukasz@langa.pl>
parents: 84114
diff changeset
611
a2672dc7c805 Issue #18244: Adopt C3-based linearization in functools.singledispatch for improved ABC support
Łukasz Langa <lukasz@langa.pl>
parents: 84114
diff changeset
612 def _c3_mro(cls, abcs=None):
a2672dc7c805 Issue #18244: Adopt C3-based linearization in functools.singledispatch for improved ABC support
Łukasz Langa <lukasz@langa.pl>
parents: 84114
diff changeset
613 """Computes the method resolution order using extended C3 linearization.
a2672dc7c805 Issue #18244: Adopt C3-based linearization in functools.singledispatch for improved ABC support
Łukasz Langa <lukasz@langa.pl>
parents: 84114
diff changeset
614
a2672dc7c805 Issue #18244: Adopt C3-based linearization in functools.singledispatch for improved ABC support
Łukasz Langa <lukasz@langa.pl>
parents: 84114
diff changeset
615 If no *abcs* are given, the algorithm works exactly like the built-in C3
a2672dc7c805 Issue #18244: Adopt C3-based linearization in functools.singledispatch for improved ABC support
Łukasz Langa <lukasz@langa.pl>
parents: 84114
diff changeset
616 linearization used for method resolution.
a2672dc7c805 Issue #18244: Adopt C3-based linearization in functools.singledispatch for improved ABC support
Łukasz Langa <lukasz@langa.pl>
parents: 84114
diff changeset
617
a2672dc7c805 Issue #18244: Adopt C3-based linearization in functools.singledispatch for improved ABC support
Łukasz Langa <lukasz@langa.pl>
parents: 84114
diff changeset
618 If given, *abcs* is a list of abstract base classes that should be inserted
a2672dc7c805 Issue #18244: Adopt C3-based linearization in functools.singledispatch for improved ABC support
Łukasz Langa <lukasz@langa.pl>
parents: 84114
diff changeset
619 into the resulting MRO. Unrelated ABCs are ignored and don't end up in the
a2672dc7c805 Issue #18244: Adopt C3-based linearization in functools.singledispatch for improved ABC support
Łukasz Langa <lukasz@langa.pl>
parents: 84114
diff changeset
620 result. The algorithm inserts ABCs where their functionality is introduced,
a2672dc7c805 Issue #18244: Adopt C3-based linearization in functools.singledispatch for improved ABC support
Łukasz Langa <lukasz@langa.pl>
parents: 84114
diff changeset
621 i.e. issubclass(cls, abc) returns True for the class itself but returns
a2672dc7c805 Issue #18244: Adopt C3-based linearization in functools.singledispatch for improved ABC support
Łukasz Langa <lukasz@langa.pl>
parents: 84114
diff changeset
622 False for all its direct base classes. Implicit ABCs for a given class
a2672dc7c805 Issue #18244: Adopt C3-based linearization in functools.singledispatch for improved ABC support
Łukasz Langa <lukasz@langa.pl>
parents: 84114
diff changeset
623 (either registered or inferred from the presence of a special method like
a2672dc7c805 Issue #18244: Adopt C3-based linearization in functools.singledispatch for improved ABC support
Łukasz Langa <lukasz@langa.pl>
parents: 84114
diff changeset
624 __len__) are inserted directly after the last ABC explicitly listed in the
a2672dc7c805 Issue #18244: Adopt C3-based linearization in functools.singledispatch for improved ABC support
Łukasz Langa <lukasz@langa.pl>
parents: 84114
diff changeset
625 MRO of said class. If two implicit ABCs end up next to each other in the
a2672dc7c805 Issue #18244: Adopt C3-based linearization in functools.singledispatch for improved ABC support
Łukasz Langa <lukasz@langa.pl>
parents: 84114
diff changeset
626 resulting MRO, their ordering depends on the order of types in *abcs*.
a2672dc7c805 Issue #18244: Adopt C3-based linearization in functools.singledispatch for improved ABC support
Łukasz Langa <lukasz@langa.pl>
parents: 84114
diff changeset
627
a2672dc7c805 Issue #18244: Adopt C3-based linearization in functools.singledispatch for improved ABC support
Łukasz Langa <lukasz@langa.pl>
parents: 84114
diff changeset
628 """
a2672dc7c805 Issue #18244: Adopt C3-based linearization in functools.singledispatch for improved ABC support
Łukasz Langa <lukasz@langa.pl>
parents: 84114
diff changeset
629 for i, base in enumerate(reversed(cls.__bases__)):
a2672dc7c805 Issue #18244: Adopt C3-based linearization in functools.singledispatch for improved ABC support
Łukasz Langa <lukasz@langa.pl>
parents: 84114
diff changeset
630 if hasattr(base, '__abstractmethods__'):
a2672dc7c805 Issue #18244: Adopt C3-based linearization in functools.singledispatch for improved ABC support
Łukasz Langa <lukasz@langa.pl>
parents: 84114
diff changeset
631 boundary = len(cls.__bases__) - i
a2672dc7c805 Issue #18244: Adopt C3-based linearization in functools.singledispatch for improved ABC support
Łukasz Langa <lukasz@langa.pl>
parents: 84114
diff changeset
632 break # Bases up to the last explicit ABC are considered first.
a2672dc7c805 Issue #18244: Adopt C3-based linearization in functools.singledispatch for improved ABC support
Łukasz Langa <lukasz@langa.pl>
parents: 84114
diff changeset
633 else:
a2672dc7c805 Issue #18244: Adopt C3-based linearization in functools.singledispatch for improved ABC support
Łukasz Langa <lukasz@langa.pl>
parents: 84114
diff changeset
634 boundary = 0
a2672dc7c805 Issue #18244: Adopt C3-based linearization in functools.singledispatch for improved ABC support
Łukasz Langa <lukasz@langa.pl>
parents: 84114
diff changeset
635 abcs = list(abcs) if abcs else []
a2672dc7c805 Issue #18244: Adopt C3-based linearization in functools.singledispatch for improved ABC support
Łukasz Langa <lukasz@langa.pl>
parents: 84114
diff changeset
636 explicit_bases = list(cls.__bases__[:boundary])
a2672dc7c805 Issue #18244: Adopt C3-based linearization in functools.singledispatch for improved ABC support
Łukasz Langa <lukasz@langa.pl>
parents: 84114
diff changeset
637 abstract_bases = []
a2672dc7c805 Issue #18244: Adopt C3-based linearization in functools.singledispatch for improved ABC support
Łukasz Langa <lukasz@langa.pl>
parents: 84114
diff changeset
638 other_bases = list(cls.__bases__[boundary:])
a2672dc7c805 Issue #18244: Adopt C3-based linearization in functools.singledispatch for improved ABC support
Łukasz Langa <lukasz@langa.pl>
parents: 84114
diff changeset
639 for base in abcs:
a2672dc7c805 Issue #18244: Adopt C3-based linearization in functools.singledispatch for improved ABC support
Łukasz Langa <lukasz@langa.pl>
parents: 84114
diff changeset
640 if issubclass(cls, base) and not any(
a2672dc7c805 Issue #18244: Adopt C3-based linearization in functools.singledispatch for improved ABC support
Łukasz Langa <lukasz@langa.pl>
parents: 84114
diff changeset
641 issubclass(b, base) for b in cls.__bases__
a2672dc7c805 Issue #18244: Adopt C3-based linearization in functools.singledispatch for improved ABC support
Łukasz Langa <lukasz@langa.pl>
parents: 84114
diff changeset
642 ):
a2672dc7c805 Issue #18244: Adopt C3-based linearization in functools.singledispatch for improved ABC support
Łukasz Langa <lukasz@langa.pl>
parents: 84114
diff changeset
643 # If *cls* is the class that introduces behaviour described by
a2672dc7c805 Issue #18244: Adopt C3-based linearization in functools.singledispatch for improved ABC support
Łukasz Langa <lukasz@langa.pl>
parents: 84114
diff changeset
644 # an ABC *base*, insert said ABC to its MRO.
a2672dc7c805 Issue #18244: Adopt C3-based linearization in functools.singledispatch for improved ABC support
Łukasz Langa <lukasz@langa.pl>
parents: 84114
diff changeset
645 abstract_bases.append(base)
a2672dc7c805 Issue #18244: Adopt C3-based linearization in functools.singledispatch for improved ABC support
Łukasz Langa <lukasz@langa.pl>
parents: 84114
diff changeset
646 for base in abstract_bases:
a2672dc7c805 Issue #18244: Adopt C3-based linearization in functools.singledispatch for improved ABC support
Łukasz Langa <lukasz@langa.pl>
parents: 84114
diff changeset
647 abcs.remove(base)
a2672dc7c805 Issue #18244: Adopt C3-based linearization in functools.singledispatch for improved ABC support
Łukasz Langa <lukasz@langa.pl>
parents: 84114
diff changeset
648 explicit_c3_mros = [_c3_mro(base, abcs=abcs) for base in explicit_bases]
a2672dc7c805 Issue #18244: Adopt C3-based linearization in functools.singledispatch for improved ABC support
Łukasz Langa <lukasz@langa.pl>
parents: 84114
diff changeset
649 abstract_c3_mros = [_c3_mro(base, abcs=abcs) for base in abstract_bases]
a2672dc7c805 Issue #18244: Adopt C3-based linearization in functools.singledispatch for improved ABC support
Łukasz Langa <lukasz@langa.pl>
parents: 84114
diff changeset
650 other_c3_mros = [_c3_mro(base, abcs=abcs) for base in other_bases]
a2672dc7c805 Issue #18244: Adopt C3-based linearization in functools.singledispatch for improved ABC support
Łukasz Langa <lukasz@langa.pl>
parents: 84114
diff changeset
651 return _c3_merge(
a2672dc7c805 Issue #18244: Adopt C3-based linearization in functools.singledispatch for improved ABC support
Łukasz Langa <lukasz@langa.pl>
parents: 84114
diff changeset
652 [[cls]] +
a2672dc7c805 Issue #18244: Adopt C3-based linearization in functools.singledispatch for improved ABC support
Łukasz Langa <lukasz@langa.pl>
parents: 84114
diff changeset
653 explicit_c3_mros + abstract_c3_mros + other_c3_mros +
a2672dc7c805 Issue #18244: Adopt C3-based linearization in functools.singledispatch for improved ABC support
Łukasz Langa <lukasz@langa.pl>
parents: 84114
diff changeset
654 [explicit_bases] + [abstract_bases] + [other_bases]
a2672dc7c805 Issue #18244: Adopt C3-based linearization in functools.singledispatch for improved ABC support
Łukasz Langa <lukasz@langa.pl>
parents: 84114
diff changeset
655 )
a2672dc7c805 Issue #18244: Adopt C3-based linearization in functools.singledispatch for improved ABC support
Łukasz Langa <lukasz@langa.pl>
parents: 84114
diff changeset
656
a2672dc7c805 Issue #18244: Adopt C3-based linearization in functools.singledispatch for improved ABC support
Łukasz Langa <lukasz@langa.pl>
parents: 84114
diff changeset
657 def _compose_mro(cls, types):
a2672dc7c805 Issue #18244: Adopt C3-based linearization in functools.singledispatch for improved ABC support
Łukasz Langa <lukasz@langa.pl>
parents: 84114
diff changeset
658 """Calculates the method resolution order for a given class *cls*.
a2672dc7c805 Issue #18244: Adopt C3-based linearization in functools.singledispatch for improved ABC support
Łukasz Langa <lukasz@langa.pl>
parents: 84114
diff changeset
659
a2672dc7c805 Issue #18244: Adopt C3-based linearization in functools.singledispatch for improved ABC support
Łukasz Langa <lukasz@langa.pl>
parents: 84114
diff changeset
660 Includes relevant abstract base classes (with their respective bases) from
a2672dc7c805 Issue #18244: Adopt C3-based linearization in functools.singledispatch for improved ABC support
Łukasz Langa <lukasz@langa.pl>
parents: 84114
diff changeset
661 the *types* iterable. Uses a modified C3 linearization algorithm.
84039
dfcb64f51f7b Add reference implementation for PEP 443
Łukasz Langa <lukasz@langa.pl>
parents: 82561
diff changeset
662
dfcb64f51f7b Add reference implementation for PEP 443
Łukasz Langa <lukasz@langa.pl>
parents: 82561
diff changeset
663 """
dfcb64f51f7b Add reference implementation for PEP 443
Łukasz Langa <lukasz@langa.pl>
parents: 82561
diff changeset
664 bases = set(cls.__mro__)
84411
a2672dc7c805 Issue #18244: Adopt C3-based linearization in functools.singledispatch for improved ABC support
Łukasz Langa <lukasz@langa.pl>
parents: 84114
diff changeset
665 # Remove entries which are already present in the __mro__ or unrelated.
a2672dc7c805 Issue #18244: Adopt C3-based linearization in functools.singledispatch for improved ABC support
Łukasz Langa <lukasz@langa.pl>
parents: 84114
diff changeset
666 def is_related(typ):
a2672dc7c805 Issue #18244: Adopt C3-based linearization in functools.singledispatch for improved ABC support
Łukasz Langa <lukasz@langa.pl>
parents: 84114
diff changeset
667 return (typ not in bases and hasattr(typ, '__mro__')
a2672dc7c805 Issue #18244: Adopt C3-based linearization in functools.singledispatch for improved ABC support
Łukasz Langa <lukasz@langa.pl>
parents: 84114
diff changeset
668 and issubclass(cls, typ))
a2672dc7c805 Issue #18244: Adopt C3-based linearization in functools.singledispatch for improved ABC support
Łukasz Langa <lukasz@langa.pl>
parents: 84114
diff changeset
669 types = [n for n in types if is_related(n)]
a2672dc7c805 Issue #18244: Adopt C3-based linearization in functools.singledispatch for improved ABC support
Łukasz Langa <lukasz@langa.pl>
parents: 84114
diff changeset
670 # Remove entries which are strict bases of other entries (they will end up
a2672dc7c805 Issue #18244: Adopt C3-based linearization in functools.singledispatch for improved ABC support
Łukasz Langa <lukasz@langa.pl>
parents: 84114
diff changeset
671 # in the MRO anyway.
a2672dc7c805 Issue #18244: Adopt C3-based linearization in functools.singledispatch for improved ABC support
Łukasz Langa <lukasz@langa.pl>
parents: 84114
diff changeset
672 def is_strict_base(typ):
a2672dc7c805 Issue #18244: Adopt C3-based linearization in functools.singledispatch for improved ABC support
Łukasz Langa <lukasz@langa.pl>
parents: 84114
diff changeset
673 for other in types:
a2672dc7c805 Issue #18244: Adopt C3-based linearization in functools.singledispatch for improved ABC support
Łukasz Langa <lukasz@langa.pl>
parents: 84114
diff changeset
674 if typ != other and typ in other.__mro__:
a2672dc7c805 Issue #18244: Adopt C3-based linearization in functools.singledispatch for improved ABC support
Łukasz Langa <lukasz@langa.pl>
parents: 84114
diff changeset
675 return True
a2672dc7c805 Issue #18244: Adopt C3-based linearization in functools.singledispatch for improved ABC support
Łukasz Langa <lukasz@langa.pl>
parents: 84114
diff changeset
676 return False
a2672dc7c805 Issue #18244: Adopt C3-based linearization in functools.singledispatch for improved ABC support
Łukasz Langa <lukasz@langa.pl>
parents: 84114
diff changeset
677 types = [n for n in types if not is_strict_base(n)]
a2672dc7c805 Issue #18244: Adopt C3-based linearization in functools.singledispatch for improved ABC support
Łukasz Langa <lukasz@langa.pl>
parents: 84114
diff changeset
678 # Subclasses of the ABCs in *types* which are also implemented by
a2672dc7c805 Issue #18244: Adopt C3-based linearization in functools.singledispatch for improved ABC support
Łukasz Langa <lukasz@langa.pl>
parents: 84114
diff changeset
679 # *cls* can be used to stabilize ABC ordering.
a2672dc7c805 Issue #18244: Adopt C3-based linearization in functools.singledispatch for improved ABC support
Łukasz Langa <lukasz@langa.pl>
parents: 84114
diff changeset
680 type_set = set(types)
a2672dc7c805 Issue #18244: Adopt C3-based linearization in functools.singledispatch for improved ABC support
Łukasz Langa <lukasz@langa.pl>
parents: 84114
diff changeset
681 mro = []
a2672dc7c805 Issue #18244: Adopt C3-based linearization in functools.singledispatch for improved ABC support
Łukasz Langa <lukasz@langa.pl>
parents: 84114
diff changeset
682 for typ in types:
a2672dc7c805 Issue #18244: Adopt C3-based linearization in functools.singledispatch for improved ABC support
Łukasz Langa <lukasz@langa.pl>
parents: 84114
diff changeset
683 found = []
a2672dc7c805 Issue #18244: Adopt C3-based linearization in functools.singledispatch for improved ABC support
Łukasz Langa <lukasz@langa.pl>
parents: 84114
diff changeset
684 for sub in typ.__subclasses__():
a2672dc7c805 Issue #18244: Adopt C3-based linearization in functools.singledispatch for improved ABC support
Łukasz Langa <lukasz@langa.pl>
parents: 84114
diff changeset
685 if sub not in bases and issubclass(cls, sub):
a2672dc7c805 Issue #18244: Adopt C3-based linearization in functools.singledispatch for improved ABC support
Łukasz Langa <lukasz@langa.pl>
parents: 84114
diff changeset
686 found.append([s for s in sub.__mro__ if s in type_set])
a2672dc7c805 Issue #18244: Adopt C3-based linearization in functools.singledispatch for improved ABC support
Łukasz Langa <lukasz@langa.pl>
parents: 84114
diff changeset
687 if not found:
a2672dc7c805 Issue #18244: Adopt C3-based linearization in functools.singledispatch for improved ABC support
Łukasz Langa <lukasz@langa.pl>
parents: 84114
diff changeset
688 mro.append(typ)
a2672dc7c805 Issue #18244: Adopt C3-based linearization in functools.singledispatch for improved ABC support
Łukasz Langa <lukasz@langa.pl>
parents: 84114
diff changeset
689 continue
a2672dc7c805 Issue #18244: Adopt C3-based linearization in functools.singledispatch for improved ABC support
Łukasz Langa <lukasz@langa.pl>
parents: 84114
diff changeset
690 # Favor subclasses with the biggest number of useful bases
a2672dc7c805 Issue #18244: Adopt C3-based linearization in functools.singledispatch for improved ABC support
Łukasz Langa <lukasz@langa.pl>
parents: 84114
diff changeset
691 found.sort(key=len, reverse=True)
a2672dc7c805 Issue #18244: Adopt C3-based linearization in functools.singledispatch for improved ABC support
Łukasz Langa <lukasz@langa.pl>
parents: 84114
diff changeset
692 for sub in found:
a2672dc7c805 Issue #18244: Adopt C3-based linearization in functools.singledispatch for improved ABC support
Łukasz Langa <lukasz@langa.pl>
parents: 84114
diff changeset
693 for subcls in sub:
a2672dc7c805 Issue #18244: Adopt C3-based linearization in functools.singledispatch for improved ABC support
Łukasz Langa <lukasz@langa.pl>
parents: 84114
diff changeset
694 if subcls not in mro:
a2672dc7c805 Issue #18244: Adopt C3-based linearization in functools.singledispatch for improved ABC support
Łukasz Langa <lukasz@langa.pl>
parents: 84114
diff changeset
695 mro.append(subcls)
a2672dc7c805 Issue #18244: Adopt C3-based linearization in functools.singledispatch for improved ABC support
Łukasz Langa <lukasz@langa.pl>
parents: 84114
diff changeset
696 return _c3_mro(cls, abcs=mro)
84039
dfcb64f51f7b Add reference implementation for PEP 443
Łukasz Langa <lukasz@langa.pl>
parents: 82561
diff changeset
697
dfcb64f51f7b Add reference implementation for PEP 443
Łukasz Langa <lukasz@langa.pl>
parents: 82561
diff changeset
698 def _find_impl(cls, registry):
84411
a2672dc7c805 Issue #18244: Adopt C3-based linearization in functools.singledispatch for improved ABC support
Łukasz Langa <lukasz@langa.pl>
parents: 84114
diff changeset
699 """Returns the best matching implementation from *registry* for type *cls*.
84039
dfcb64f51f7b Add reference implementation for PEP 443
Łukasz Langa <lukasz@langa.pl>
parents: 82561
diff changeset
700
84411
a2672dc7c805 Issue #18244: Adopt C3-based linearization in functools.singledispatch for improved ABC support
Łukasz Langa <lukasz@langa.pl>
parents: 84114
diff changeset
701 Where there is no registered implementation for a specific type, its method
a2672dc7c805 Issue #18244: Adopt C3-based linearization in functools.singledispatch for improved ABC support
Łukasz Langa <lukasz@langa.pl>
parents: 84114
diff changeset
702 resolution order is used to find a more generic implementation.
a2672dc7c805 Issue #18244: Adopt C3-based linearization in functools.singledispatch for improved ABC support
Łukasz Langa <lukasz@langa.pl>
parents: 84114
diff changeset
703
a2672dc7c805 Issue #18244: Adopt C3-based linearization in functools.singledispatch for improved ABC support
Łukasz Langa <lukasz@langa.pl>
parents: 84114
diff changeset
704 Note: if *registry* does not contain an implementation for the base
a2672dc7c805 Issue #18244: Adopt C3-based linearization in functools.singledispatch for improved ABC support
Łukasz Langa <lukasz@langa.pl>
parents: 84114
diff changeset
705 *object* type, this function may return None.
84039
dfcb64f51f7b Add reference implementation for PEP 443
Łukasz Langa <lukasz@langa.pl>
parents: 82561
diff changeset
706
dfcb64f51f7b Add reference implementation for PEP 443
Łukasz Langa <lukasz@langa.pl>
parents: 82561
diff changeset
707 """
dfcb64f51f7b Add reference implementation for PEP 443
Łukasz Langa <lukasz@langa.pl>
parents: 82561
diff changeset
708 mro = _compose_mro(cls, registry.keys())
dfcb64f51f7b Add reference implementation for PEP 443
Łukasz Langa <lukasz@langa.pl>
parents: 82561
diff changeset
709 match = None
dfcb64f51f7b Add reference implementation for PEP 443
Łukasz Langa <lukasz@langa.pl>
parents: 82561
diff changeset
710 for t in mro:
dfcb64f51f7b Add reference implementation for PEP 443
Łukasz Langa <lukasz@langa.pl>
parents: 82561
diff changeset
711 if match is not None:
84411
a2672dc7c805 Issue #18244: Adopt C3-based linearization in functools.singledispatch for improved ABC support
Łukasz Langa <lukasz@langa.pl>
parents: 84114
diff changeset
712 # If *match* is an implicit ABC but there is another unrelated,
a2672dc7c805 Issue #18244: Adopt C3-based linearization in functools.singledispatch for improved ABC support
Łukasz Langa <lukasz@langa.pl>
parents: 84114
diff changeset
713 # equally matching implicit ABC, refuse the temptation to guess.
a2672dc7c805 Issue #18244: Adopt C3-based linearization in functools.singledispatch for improved ABC support
Łukasz Langa <lukasz@langa.pl>
parents: 84114
diff changeset
714 if (t in registry and t not in cls.__mro__
a2672dc7c805 Issue #18244: Adopt C3-based linearization in functools.singledispatch for improved ABC support
Łukasz Langa <lukasz@langa.pl>
parents: 84114
diff changeset
715 and match not in cls.__mro__
a2672dc7c805 Issue #18244: Adopt C3-based linearization in functools.singledispatch for improved ABC support
Łukasz Langa <lukasz@langa.pl>
parents: 84114
diff changeset
716 and not issubclass(match, t)):
84039
dfcb64f51f7b Add reference implementation for PEP 443
Łukasz Langa <lukasz@langa.pl>
parents: 82561
diff changeset
717 raise RuntimeError("Ambiguous dispatch: {} or {}".format(
dfcb64f51f7b Add reference implementation for PEP 443
Łukasz Langa <lukasz@langa.pl>
parents: 82561
diff changeset
718 match, t))
dfcb64f51f7b Add reference implementation for PEP 443
Łukasz Langa <lukasz@langa.pl>
parents: 82561
diff changeset
719 break
dfcb64f51f7b Add reference implementation for PEP 443
Łukasz Langa <lukasz@langa.pl>
parents: 82561
diff changeset
720 if t in registry:
dfcb64f51f7b Add reference implementation for PEP 443
Łukasz Langa <lukasz@langa.pl>
parents: 82561
diff changeset
721 match = t
dfcb64f51f7b Add reference implementation for PEP 443
Łukasz Langa <lukasz@langa.pl>
parents: 82561
diff changeset
722 return registry.get(match)
dfcb64f51f7b Add reference implementation for PEP 443
Łukasz Langa <lukasz@langa.pl>
parents: 82561
diff changeset
723
dfcb64f51f7b Add reference implementation for PEP 443
Łukasz Langa <lukasz@langa.pl>
parents: 82561
diff changeset
724 def singledispatch(func):
dfcb64f51f7b Add reference implementation for PEP 443
Łukasz Langa <lukasz@langa.pl>
parents: 82561
diff changeset
725 """Single-dispatch generic function decorator.
dfcb64f51f7b Add reference implementation for PEP 443
Łukasz Langa <lukasz@langa.pl>
parents: 82561
diff changeset
726
dfcb64f51f7b Add reference implementation for PEP 443
Łukasz Langa <lukasz@langa.pl>
parents: 82561
diff changeset
727 Transforms a function into a generic function, which can have different
dfcb64f51f7b Add reference implementation for PEP 443
Łukasz Langa <lukasz@langa.pl>
parents: 82561
diff changeset
728 behaviours depending upon the type of its first argument. The decorated
dfcb64f51f7b Add reference implementation for PEP 443
Łukasz Langa <lukasz@langa.pl>
parents: 82561
diff changeset
729 function acts as the default implementation, and additional
84411
a2672dc7c805 Issue #18244: Adopt C3-based linearization in functools.singledispatch for improved ABC support
Łukasz Langa <lukasz@langa.pl>
parents: 84114
diff changeset
730 implementations can be registered using the register() attribute of the
a2672dc7c805 Issue #18244: Adopt C3-based linearization in functools.singledispatch for improved ABC support
Łukasz Langa <lukasz@langa.pl>
parents: 84114
diff changeset
731 generic function.
84039
dfcb64f51f7b Add reference implementation for PEP 443
Łukasz Langa <lukasz@langa.pl>
parents: 82561
diff changeset
732
dfcb64f51f7b Add reference implementation for PEP 443
Łukasz Langa <lukasz@langa.pl>
parents: 82561
diff changeset
733 """
dfcb64f51f7b Add reference implementation for PEP 443
Łukasz Langa <lukasz@langa.pl>
parents: 82561
diff changeset
734 registry = {}
dfcb64f51f7b Add reference implementation for PEP 443
Łukasz Langa <lukasz@langa.pl>
parents: 82561
diff changeset
735 dispatch_cache = WeakKeyDictionary()
dfcb64f51f7b Add reference implementation for PEP 443
Łukasz Langa <lukasz@langa.pl>
parents: 82561
diff changeset
736 cache_token = None
dfcb64f51f7b Add reference implementation for PEP 443
Łukasz Langa <lukasz@langa.pl>
parents: 82561
diff changeset
737
84411
a2672dc7c805 Issue #18244: Adopt C3-based linearization in functools.singledispatch for improved ABC support
Łukasz Langa <lukasz@langa.pl>
parents: 84114
diff changeset
738 def dispatch(cls):
a2672dc7c805 Issue #18244: Adopt C3-based linearization in functools.singledispatch for improved ABC support
Łukasz Langa <lukasz@langa.pl>
parents: 84114
diff changeset
739 """generic_func.dispatch(cls) -> <function implementation>
84039
dfcb64f51f7b Add reference implementation for PEP 443
Łukasz Langa <lukasz@langa.pl>
parents: 82561
diff changeset
740
dfcb64f51f7b Add reference implementation for PEP 443
Łukasz Langa <lukasz@langa.pl>
parents: 82561
diff changeset
741 Runs the dispatch algorithm to return the best available implementation
84411
a2672dc7c805 Issue #18244: Adopt C3-based linearization in functools.singledispatch for improved ABC support
Łukasz Langa <lukasz@langa.pl>
parents: 84114
diff changeset
742 for the given *cls* registered on *generic_func*.
84039
dfcb64f51f7b Add reference implementation for PEP 443
Łukasz Langa <lukasz@langa.pl>
parents: 82561
diff changeset
743
dfcb64f51f7b Add reference implementation for PEP 443
Łukasz Langa <lukasz@langa.pl>
parents: 82561
diff changeset
744 """
dfcb64f51f7b Add reference implementation for PEP 443
Łukasz Langa <lukasz@langa.pl>
parents: 82561
diff changeset
745 nonlocal cache_token
dfcb64f51f7b Add reference implementation for PEP 443
Łukasz Langa <lukasz@langa.pl>
parents: 82561
diff changeset
746 if cache_token is not None:
dfcb64f51f7b Add reference implementation for PEP 443
Łukasz Langa <lukasz@langa.pl>
parents: 82561
diff changeset
747 current_token = get_cache_token()
dfcb64f51f7b Add reference implementation for PEP 443
Łukasz Langa <lukasz@langa.pl>
parents: 82561
diff changeset
748 if cache_token != current_token:
dfcb64f51f7b Add reference implementation for PEP 443
Łukasz Langa <lukasz@langa.pl>
parents: 82561
diff changeset
749 dispatch_cache.clear()
dfcb64f51f7b Add reference implementation for PEP 443
Łukasz Langa <lukasz@langa.pl>
parents: 82561
diff changeset
750 cache_token = current_token
dfcb64f51f7b Add reference implementation for PEP 443
Łukasz Langa <lukasz@langa.pl>
parents: 82561
diff changeset
751 try:
84411
a2672dc7c805 Issue #18244: Adopt C3-based linearization in functools.singledispatch for improved ABC support
Łukasz Langa <lukasz@langa.pl>
parents: 84114
diff changeset
752 impl = dispatch_cache[cls]
84039
dfcb64f51f7b Add reference implementation for PEP 443
Łukasz Langa <lukasz@langa.pl>
parents: 82561
diff changeset
753 except KeyError:
dfcb64f51f7b Add reference implementation for PEP 443
Łukasz Langa <lukasz@langa.pl>
parents: 82561
diff changeset
754 try:
84411
a2672dc7c805 Issue #18244: Adopt C3-based linearization in functools.singledispatch for improved ABC support
Łukasz Langa <lukasz@langa.pl>
parents: 84114
diff changeset
755 impl = registry[cls]
84039
dfcb64f51f7b Add reference implementation for PEP 443
Łukasz Langa <lukasz@langa.pl>
parents: 82561
diff changeset
756 except KeyError:
84411
a2672dc7c805 Issue #18244: Adopt C3-based linearization in functools.singledispatch for improved ABC support
Łukasz Langa <lukasz@langa.pl>
parents: 84114
diff changeset
757 impl = _find_impl(cls, registry)
a2672dc7c805 Issue #18244: Adopt C3-based linearization in functools.singledispatch for improved ABC support
Łukasz Langa <lukasz@langa.pl>
parents: 84114
diff changeset
758 dispatch_cache[cls] = impl
84039
dfcb64f51f7b Add reference implementation for PEP 443
Łukasz Langa <lukasz@langa.pl>
parents: 82561
diff changeset
759 return impl
dfcb64f51f7b Add reference implementation for PEP 443
Łukasz Langa <lukasz@langa.pl>
parents: 82561
diff changeset
760
84411
a2672dc7c805 Issue #18244: Adopt C3-based linearization in functools.singledispatch for improved ABC support
Łukasz Langa <lukasz@langa.pl>
parents: 84114
diff changeset
761 def register(cls, func=None):
a2672dc7c805 Issue #18244: Adopt C3-based linearization in functools.singledispatch for improved ABC support
Łukasz Langa <lukasz@langa.pl>
parents: 84114
diff changeset
762 """generic_func.register(cls, func) -> func
84039
dfcb64f51f7b Add reference implementation for PEP 443
Łukasz Langa <lukasz@langa.pl>
parents: 82561
diff changeset
763
84411
a2672dc7c805 Issue #18244: Adopt C3-based linearization in functools.singledispatch for improved ABC support
Łukasz Langa <lukasz@langa.pl>
parents: 84114
diff changeset
764 Registers a new implementation for the given *cls* on a *generic_func*.
84039
dfcb64f51f7b Add reference implementation for PEP 443
Łukasz Langa <lukasz@langa.pl>
parents: 82561
diff changeset
765
dfcb64f51f7b Add reference implementation for PEP 443
Łukasz Langa <lukasz@langa.pl>
parents: 82561
diff changeset
766 """
dfcb64f51f7b Add reference implementation for PEP 443
Łukasz Langa <lukasz@langa.pl>
parents: 82561
diff changeset
767 nonlocal cache_token
dfcb64f51f7b Add reference implementation for PEP 443
Łukasz Langa <lukasz@langa.pl>
parents: 82561
diff changeset
768 if func is None:
84411
a2672dc7c805 Issue #18244: Adopt C3-based linearization in functools.singledispatch for improved ABC support
Łukasz Langa <lukasz@langa.pl>
parents: 84114
diff changeset
769 return lambda f: register(cls, f)
a2672dc7c805 Issue #18244: Adopt C3-based linearization in functools.singledispatch for improved ABC support
Łukasz Langa <lukasz@langa.pl>
parents: 84114
diff changeset
770 registry[cls] = func
a2672dc7c805 Issue #18244: Adopt C3-based linearization in functools.singledispatch for improved ABC support
Łukasz Langa <lukasz@langa.pl>
parents: 84114
diff changeset
771 if cache_token is None and hasattr(cls, '__abstractmethods__'):
84039
dfcb64f51f7b Add reference implementation for PEP 443
Łukasz Langa <lukasz@langa.pl>
parents: 82561
diff changeset
772 cache_token = get_cache_token()
dfcb64f51f7b Add reference implementation for PEP 443
Łukasz Langa <lukasz@langa.pl>
parents: 82561
diff changeset
773 dispatch_cache.clear()
dfcb64f51f7b Add reference implementation for PEP 443
Łukasz Langa <lukasz@langa.pl>
parents: 82561
diff changeset
774 return func
dfcb64f51f7b Add reference implementation for PEP 443
Łukasz Langa <lukasz@langa.pl>
parents: 82561
diff changeset
775
dfcb64f51f7b Add reference implementation for PEP 443
Łukasz Langa <lukasz@langa.pl>
parents: 82561
diff changeset
776 def wrapper(*args, **kw):
dfcb64f51f7b Add reference implementation for PEP 443
Łukasz Langa <lukasz@langa.pl>
parents: 82561
diff changeset
777 return dispatch(args[0].__class__)(*args, **kw)
dfcb64f51f7b Add reference implementation for PEP 443
Łukasz Langa <lukasz@langa.pl>
parents: 82561
diff changeset
778
dfcb64f51f7b Add reference implementation for PEP 443
Łukasz Langa <lukasz@langa.pl>
parents: 82561
diff changeset
779 registry[object] = func
dfcb64f51f7b Add reference implementation for PEP 443
Łukasz Langa <lukasz@langa.pl>
parents: 82561
diff changeset
780 wrapper.register = register
dfcb64f51f7b Add reference implementation for PEP 443
Łukasz Langa <lukasz@langa.pl>
parents: 82561
diff changeset
781 wrapper.dispatch = dispatch
dfcb64f51f7b Add reference implementation for PEP 443
Łukasz Langa <lukasz@langa.pl>
parents: 82561
diff changeset
782 wrapper.registry = MappingProxyType(registry)
dfcb64f51f7b Add reference implementation for PEP 443
Łukasz Langa <lukasz@langa.pl>
parents: 82561
diff changeset
783 wrapper._clear_cache = dispatch_cache.clear
dfcb64f51f7b Add reference implementation for PEP 443
Łukasz Langa <lukasz@langa.pl>
parents: 82561
diff changeset
784 update_wrapper(wrapper, func)
dfcb64f51f7b Add reference implementation for PEP 443
Łukasz Langa <lukasz@langa.pl>
parents: 82561
diff changeset
785 return wrapper