|
12 | 12 | __all__ = ['update_wrapper', 'wraps', 'WRAPPER_ASSIGNMENTS', 'WRAPPER_UPDATES', |
13 | 13 | 'total_ordering', 'cache', 'cmp_to_key', 'lru_cache', 'reduce', |
14 | 14 | 'partial', 'partialmethod', 'singledispatch', 'singledispatchmethod', |
15 | | - 'cached_property', 'Placeholder'] |
| 15 | + 'cached_method', 'cached_property', 'Placeholder'] |
16 | 16 |
|
17 | 17 | from abc import get_cache_token |
18 | 18 | from collections import namedtuple |
@@ -1127,58 +1127,6 @@ def __wrapped__(self): |
1127 | 1127 | def register(self): |
1128 | 1128 | return self._unbound.register |
1129 | 1129 |
|
1130 | | - |
1131 | | -################################################################################ |
1132 | | -### cached_property() - property result cached as instance attribute |
1133 | | -################################################################################ |
1134 | | - |
1135 | | -_NOT_FOUND = object() |
1136 | | - |
1137 | | -class cached_property: |
1138 | | - def __init__(self, func): |
1139 | | - self.func = func |
1140 | | - self.attrname = None |
1141 | | - self.__doc__ = func.__doc__ |
1142 | | - self.__module__ = func.__module__ |
1143 | | - |
1144 | | - def __set_name__(self, owner, name): |
1145 | | - if self.attrname is None: |
1146 | | - self.attrname = name |
1147 | | - elif name != self.attrname: |
1148 | | - raise TypeError( |
1149 | | - "Cannot assign the same cached_property to two different names " |
1150 | | - f"({self.attrname!r} and {name!r})." |
1151 | | - ) |
1152 | | - |
1153 | | - def __get__(self, instance, owner=None): |
1154 | | - if instance is None: |
1155 | | - return self |
1156 | | - if self.attrname is None: |
1157 | | - raise TypeError( |
1158 | | - "Cannot use cached_property instance without calling __set_name__ on it.") |
1159 | | - try: |
1160 | | - cache = instance.__dict__ |
1161 | | - except AttributeError: # not all objects have __dict__ (e.g. class defines slots) |
1162 | | - msg = ( |
1163 | | - f"No '__dict__' attribute on {type(instance).__name__!r} " |
1164 | | - f"instance to cache {self.attrname!r} property." |
1165 | | - ) |
1166 | | - raise TypeError(msg) from None |
1167 | | - val = cache.get(self.attrname, _NOT_FOUND) |
1168 | | - if val is _NOT_FOUND: |
1169 | | - val = self.func(instance) |
1170 | | - try: |
1171 | | - cache[self.attrname] = val |
1172 | | - except TypeError: |
1173 | | - msg = ( |
1174 | | - f"The '__dict__' attribute on {type(instance).__name__!r} instance " |
1175 | | - f"does not support item assignment for caching {self.attrname!r} property." |
1176 | | - ) |
1177 | | - raise TypeError(msg) from None |
1178 | | - return val |
1179 | | - |
1180 | | - __class_getitem__ = classmethod(GenericAlias) |
1181 | | - |
1182 | 1130 | ################################################################################ |
1183 | 1131 | ### cached_method -- a version of lru_cache() which uses id(self) |
1184 | 1132 | ################################################################################ |
@@ -1255,3 +1203,55 @@ def decorator(func): |
1255 | 1203 | return decorator |
1256 | 1204 | else: |
1257 | 1205 | return _cached_method(func, maxsize=maxsize, typed=typed) |
| 1206 | + |
| 1207 | + |
| 1208 | +################################################################################ |
| 1209 | +### cached_property() - property result cached as instance attribute |
| 1210 | +################################################################################ |
| 1211 | + |
| 1212 | +_NOT_FOUND = object() |
| 1213 | + |
| 1214 | +class cached_property: |
| 1215 | + def __init__(self, func): |
| 1216 | + self.func = func |
| 1217 | + self.attrname = None |
| 1218 | + self.__doc__ = func.__doc__ |
| 1219 | + self.__module__ = func.__module__ |
| 1220 | + |
| 1221 | + def __set_name__(self, owner, name): |
| 1222 | + if self.attrname is None: |
| 1223 | + self.attrname = name |
| 1224 | + elif name != self.attrname: |
| 1225 | + raise TypeError( |
| 1226 | + "Cannot assign the same cached_property to two different names " |
| 1227 | + f"({self.attrname!r} and {name!r})." |
| 1228 | + ) |
| 1229 | + |
| 1230 | + def __get__(self, instance, owner=None): |
| 1231 | + if instance is None: |
| 1232 | + return self |
| 1233 | + if self.attrname is None: |
| 1234 | + raise TypeError( |
| 1235 | + "Cannot use cached_property instance without calling __set_name__ on it.") |
| 1236 | + try: |
| 1237 | + cache = instance.__dict__ |
| 1238 | + except AttributeError: # not all objects have __dict__ (e.g. class defines slots) |
| 1239 | + msg = ( |
| 1240 | + f"No '__dict__' attribute on {type(instance).__name__!r} " |
| 1241 | + f"instance to cache {self.attrname!r} property." |
| 1242 | + ) |
| 1243 | + raise TypeError(msg) from None |
| 1244 | + val = cache.get(self.attrname, _NOT_FOUND) |
| 1245 | + if val is _NOT_FOUND: |
| 1246 | + val = self.func(instance) |
| 1247 | + try: |
| 1248 | + cache[self.attrname] = val |
| 1249 | + except TypeError: |
| 1250 | + msg = ( |
| 1251 | + f"The '__dict__' attribute on {type(instance).__name__!r} instance " |
| 1252 | + f"does not support item assignment for caching {self.attrname!r} property." |
| 1253 | + ) |
| 1254 | + raise TypeError(msg) from None |
| 1255 | + return val |
| 1256 | + |
| 1257 | + __class_getitem__ = classmethod(GenericAlias) |
0 commit comments