mirror of
				https://github.com/python/cpython.git
				synced 2025-10-31 21:51:50 +00:00 
			
		
		
		
	 c6ca368867
			
		
	
	
		c6ca368867
		
			
		
	
	
	
	
		
			
			* bpo-43780: Sync with importlib_metadata 3.10. * Add blurb * Apply changes from importlib_metadata 3.10.1.
		
			
				
	
	
		
			85 lines
		
	
	
	
		
			2.4 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
			
		
		
	
	
			85 lines
		
	
	
	
		
			2.4 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
| import types
 | |
| import functools
 | |
| 
 | |
| 
 | |
| # from jaraco.functools 3.3
 | |
| def method_cache(method, cache_wrapper=None):
 | |
|     """
 | |
|     Wrap lru_cache to support storing the cache data in the object instances.
 | |
| 
 | |
|     Abstracts the common paradigm where the method explicitly saves an
 | |
|     underscore-prefixed protected property on first call and returns that
 | |
|     subsequently.
 | |
| 
 | |
|     >>> class MyClass:
 | |
|     ...     calls = 0
 | |
|     ...
 | |
|     ...     @method_cache
 | |
|     ...     def method(self, value):
 | |
|     ...         self.calls += 1
 | |
|     ...         return value
 | |
| 
 | |
|     >>> a = MyClass()
 | |
|     >>> a.method(3)
 | |
|     3
 | |
|     >>> for x in range(75):
 | |
|     ...     res = a.method(x)
 | |
|     >>> a.calls
 | |
|     75
 | |
| 
 | |
|     Note that the apparent behavior will be exactly like that of lru_cache
 | |
|     except that the cache is stored on each instance, so values in one
 | |
|     instance will not flush values from another, and when an instance is
 | |
|     deleted, so are the cached values for that instance.
 | |
| 
 | |
|     >>> b = MyClass()
 | |
|     >>> for x in range(35):
 | |
|     ...     res = b.method(x)
 | |
|     >>> b.calls
 | |
|     35
 | |
|     >>> a.method(0)
 | |
|     0
 | |
|     >>> a.calls
 | |
|     75
 | |
| 
 | |
|     Note that if method had been decorated with ``functools.lru_cache()``,
 | |
|     a.calls would have been 76 (due to the cached value of 0 having been
 | |
|     flushed by the 'b' instance).
 | |
| 
 | |
|     Clear the cache with ``.cache_clear()``
 | |
| 
 | |
|     >>> a.method.cache_clear()
 | |
| 
 | |
|     Same for a method that hasn't yet been called.
 | |
| 
 | |
|     >>> c = MyClass()
 | |
|     >>> c.method.cache_clear()
 | |
| 
 | |
|     Another cache wrapper may be supplied:
 | |
| 
 | |
|     >>> cache = functools.lru_cache(maxsize=2)
 | |
|     >>> MyClass.method2 = method_cache(lambda self: 3, cache_wrapper=cache)
 | |
|     >>> a = MyClass()
 | |
|     >>> a.method2()
 | |
|     3
 | |
| 
 | |
|     Caution - do not subsequently wrap the method with another decorator, such
 | |
|     as ``@property``, which changes the semantics of the function.
 | |
| 
 | |
|     See also
 | |
|     http://code.activestate.com/recipes/577452-a-memoize-decorator-for-instance-methods/
 | |
|     for another implementation and additional justification.
 | |
|     """
 | |
|     cache_wrapper = cache_wrapper or functools.lru_cache()
 | |
| 
 | |
|     def wrapper(self, *args, **kwargs):
 | |
|         # it's the first call, replace the method with a cached, bound method
 | |
|         bound_method = types.MethodType(method, self)
 | |
|         cached_method = cache_wrapper(bound_method)
 | |
|         setattr(self, method.__name__, cached_method)
 | |
|         return cached_method(*args, **kwargs)
 | |
| 
 | |
|     # Support cache clear even before cache has been created.
 | |
|     wrapper.cache_clear = lambda: None
 | |
| 
 | |
|     return wrapper
 |