Mercurial > cpython-lru_cache-weakref
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 |
| 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 | 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 | 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 | 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 | 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 | 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 | 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 | 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 |
