mirror of
				https://github.com/python/cpython.git
				synced 2025-11-04 07:31:38 +00:00 
			
		
		
		
	Revert r83327. This will have to wait until after the alpha1 release.
This commit is contained in:
		
							parent
							
								
									4821ef89d4
								
							
						
					
					
						commit
						014e0ca58e
					
				
					 4 changed files with 2 additions and 193 deletions
				
			
		| 
						 | 
					@ -37,57 +37,6 @@ The :mod:`functools` module defines the following functions:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
   .. versionadded:: 3.2
 | 
					   .. versionadded:: 3.2
 | 
				
			||||||
 | 
					
 | 
				
			||||||
.. decorator:: lfu_cache(maxsize)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
   Decorator to wrap a function with a memoizing callable that saves up to the
 | 
					 | 
				
			||||||
   *maxsize* most frequent calls.  It can save time when an expensive or I/O
 | 
					 | 
				
			||||||
   bound function is periodically called with the same arguments.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
   The *maxsize* parameter defaults to 100.  Since a dictionary is used to cache
 | 
					 | 
				
			||||||
   results, the positional and keyword arguments to the function must be
 | 
					 | 
				
			||||||
   hashable.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
   The wrapped function is instrumented with two attributes, :attr:`hits`
 | 
					 | 
				
			||||||
   and :attr:`misses` which count the number of successful or unsuccessful
 | 
					 | 
				
			||||||
   cache lookups.  These statistics are helpful for tuning the *maxsize*
 | 
					 | 
				
			||||||
   parameter and for measuring the cache's effectiveness.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
   The wrapped function also has a :attr:`clear` attribute which can be
 | 
					 | 
				
			||||||
   called (with no arguments) to clear the cache.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
   A `LFU (least frequently used) cache
 | 
					 | 
				
			||||||
   <http://en.wikipedia.org/wiki/Cache_algorithms#Least-Frequently_Used>`_
 | 
					 | 
				
			||||||
   is indicated when the pattern of calls does not change over time, when
 | 
					 | 
				
			||||||
   more the most common calls already seen are the best predictors of the
 | 
					 | 
				
			||||||
   most common upcoming calls.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
   .. versionadded:: 3.2
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
.. decorator:: lru_cache(maxsize)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
   Decorator to wrap a function with a memoizing callable that saves up to the
 | 
					 | 
				
			||||||
   *maxsize* most recent calls.  It can save time when an expensive or I/O bound
 | 
					 | 
				
			||||||
   function is periodically called with the same arguments.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
   The *maxsize* parameter defaults to 100.  Since a dictionary is used to cache
 | 
					 | 
				
			||||||
   results, the positional and keyword arguments to the function must be
 | 
					 | 
				
			||||||
   hashable.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
   The wrapped function is instrumented with two attributes, :attr:`hits`
 | 
					 | 
				
			||||||
   and :attr:`misses` which count the number of successful or unsuccessful
 | 
					 | 
				
			||||||
   cache lookups.  These statistics are helpful for tuning the *maxsize*
 | 
					 | 
				
			||||||
   parameter and for measuring the cache's effectiveness.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
   The wrapped function also has a :attr:`clear` attribute which can be
 | 
					 | 
				
			||||||
   called (with no arguments) to clear the cache.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
   A `LRU (least recently used) cache
 | 
					 | 
				
			||||||
   <http://en.wikipedia.org/wiki/Cache_algorithms#Least_Recently_Used>`_
 | 
					 | 
				
			||||||
   is indicated when the pattern of calls changes over time, such as
 | 
					 | 
				
			||||||
   when more recent calls are the best predictors of upcoming calls.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
   .. versionadded:: 3.2
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
.. decorator:: total_ordering
 | 
					.. decorator:: total_ordering
 | 
				
			||||||
 | 
					
 | 
				
			||||||
   Given a class defining one or more rich comparison ordering methods, this
 | 
					   Given a class defining one or more rich comparison ordering methods, this
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -4,17 +4,10 @@
 | 
				
			||||||
# to allow utilities written in Python to be added
 | 
					# to allow utilities written in Python to be added
 | 
				
			||||||
# to the functools module.
 | 
					# to the functools module.
 | 
				
			||||||
# Written by Nick Coghlan <ncoghlan at gmail.com>
 | 
					# Written by Nick Coghlan <ncoghlan at gmail.com>
 | 
				
			||||||
# and Raymond Hettinger <python at rcn.com>
 | 
					#   Copyright (C) 2006 Python Software Foundation.
 | 
				
			||||||
#   Copyright (C) 2006-2010 Python Software Foundation.
 | 
					 | 
				
			||||||
# See C source code for _functools credits/copyright
 | 
					# See C source code for _functools credits/copyright
 | 
				
			||||||
 | 
					
 | 
				
			||||||
__all__ = ['update_wrapper', 'wraps', 'WRAPPER_ASSIGNMENTS', 'WRAPPER_UPDATES',
 | 
					 | 
				
			||||||
           'total_ordering', 'cmp_to_key', 'lfu_cache', 'lru_cache']
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
from _functools import partial, reduce
 | 
					from _functools import partial, reduce
 | 
				
			||||||
from collections import OrderedDict, Counter
 | 
					 | 
				
			||||||
from heapq import nsmallest
 | 
					 | 
				
			||||||
from operator import itemgetter
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
# update_wrapper() and wraps() are tools to help write
 | 
					# update_wrapper() and wraps() are tools to help write
 | 
				
			||||||
# wrapper functions that can handle naive introspection
 | 
					# wrapper functions that can handle naive introspection
 | 
				
			||||||
| 
						 | 
					@ -104,88 +97,3 @@ def __ne__(self, other):
 | 
				
			||||||
        def __hash__(self):
 | 
					        def __hash__(self):
 | 
				
			||||||
            raise TypeError('hash not implemented')
 | 
					            raise TypeError('hash not implemented')
 | 
				
			||||||
    return K
 | 
					    return K
 | 
				
			||||||
 | 
					 | 
				
			||||||
def lfu_cache(maxsize=100):
 | 
					 | 
				
			||||||
    '''Least-frequently-used cache decorator.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    Arguments to the cached function must be hashable.
 | 
					 | 
				
			||||||
    Cache performance statistics stored in f.hits and f.misses.
 | 
					 | 
				
			||||||
    Clear the cache using f.clear().
 | 
					 | 
				
			||||||
    http://en.wikipedia.org/wiki/Cache_algorithms#Least-Frequently_Used
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    '''
 | 
					 | 
				
			||||||
    def decorating_function(user_function):
 | 
					 | 
				
			||||||
        cache = {}                      # mapping of args to results
 | 
					 | 
				
			||||||
        use_count = Counter()           # times each key has been accessed
 | 
					 | 
				
			||||||
        kwd_mark = object()             # separate positional and keyword args
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        @wraps(user_function)
 | 
					 | 
				
			||||||
        def wrapper(*args, **kwds):
 | 
					 | 
				
			||||||
            key = args
 | 
					 | 
				
			||||||
            if kwds:
 | 
					 | 
				
			||||||
                key += (kwd_mark,) + tuple(sorted(kwds.items()))
 | 
					 | 
				
			||||||
            use_count[key] += 1         # count a use of this key
 | 
					 | 
				
			||||||
            try:
 | 
					 | 
				
			||||||
                result = cache[key]
 | 
					 | 
				
			||||||
                wrapper.hits += 1
 | 
					 | 
				
			||||||
            except KeyError:
 | 
					 | 
				
			||||||
                result = user_function(*args, **kwds)
 | 
					 | 
				
			||||||
                cache[key] = result
 | 
					 | 
				
			||||||
                wrapper.misses += 1
 | 
					 | 
				
			||||||
                if len(cache) > maxsize:
 | 
					 | 
				
			||||||
                    # purge the 10% least frequently used entries
 | 
					 | 
				
			||||||
                    for key, _ in nsmallest(maxsize // 10,
 | 
					 | 
				
			||||||
                                            use_count.items(),
 | 
					 | 
				
			||||||
                                            key=itemgetter(1)):
 | 
					 | 
				
			||||||
                        del cache[key], use_count[key]
 | 
					 | 
				
			||||||
            return result
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        def clear():
 | 
					 | 
				
			||||||
            'Clear the cache and cache statistics'
 | 
					 | 
				
			||||||
            cache.clear()
 | 
					 | 
				
			||||||
            use_count.clear()
 | 
					 | 
				
			||||||
            wrapper.hits = wrapper.misses = 0
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        wrapper.hits = wrapper.misses = 0
 | 
					 | 
				
			||||||
        wrapper.clear = clear
 | 
					 | 
				
			||||||
        return wrapper
 | 
					 | 
				
			||||||
    return decorating_function
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
def lru_cache(maxsize=100):
 | 
					 | 
				
			||||||
    '''Least-recently-used cache decorator.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    Arguments to the cached function must be hashable.
 | 
					 | 
				
			||||||
    Cache performance statistics stored in f.hits and f.misses.
 | 
					 | 
				
			||||||
    Clear the cache using f.clear().
 | 
					 | 
				
			||||||
    http://en.wikipedia.org/wiki/Cache_algorithms#Least_Recently_Used
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    '''
 | 
					 | 
				
			||||||
    def decorating_function(user_function):
 | 
					 | 
				
			||||||
        cache = OrderedDict()           # ordered least recent to most recent
 | 
					 | 
				
			||||||
        kwd_mark = object()             # separate positional and keyword args
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        @wraps(user_function)
 | 
					 | 
				
			||||||
        def wrapper(*args, **kwds):
 | 
					 | 
				
			||||||
            key = args
 | 
					 | 
				
			||||||
            if kwds:
 | 
					 | 
				
			||||||
                key += (kwd_mark,) + tuple(sorted(kwds.items()))
 | 
					 | 
				
			||||||
            try:
 | 
					 | 
				
			||||||
                result = cache.pop(key)
 | 
					 | 
				
			||||||
                wrapper.hits += 1
 | 
					 | 
				
			||||||
            except KeyError:
 | 
					 | 
				
			||||||
                result = user_function(*args, **kwds)
 | 
					 | 
				
			||||||
                wrapper.misses += 1
 | 
					 | 
				
			||||||
                if len(cache) >= maxsize:
 | 
					 | 
				
			||||||
                    cache.popitem(0)    # purge least recently used cache entry
 | 
					 | 
				
			||||||
            cache[key] = result         # record recent use of this key
 | 
					 | 
				
			||||||
            return result
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        def clear():
 | 
					 | 
				
			||||||
            'Clear the cache and cache statistics'
 | 
					 | 
				
			||||||
            cache.clear()
 | 
					 | 
				
			||||||
            wrapper.hits = wrapper.misses = 0
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        wrapper.hits = wrapper.misses = 0
 | 
					 | 
				
			||||||
        wrapper.clear = clear
 | 
					 | 
				
			||||||
        return wrapper
 | 
					 | 
				
			||||||
    return decorating_function
 | 
					 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -4,7 +4,6 @@
 | 
				
			||||||
from test import support
 | 
					from test import support
 | 
				
			||||||
from weakref import proxy
 | 
					from weakref import proxy
 | 
				
			||||||
import pickle
 | 
					import pickle
 | 
				
			||||||
from random import choice
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
@staticmethod
 | 
					@staticmethod
 | 
				
			||||||
def PythonPartial(func, *args, **keywords):
 | 
					def PythonPartial(func, *args, **keywords):
 | 
				
			||||||
| 
						 | 
					@ -455,50 +454,6 @@ def test_no_operations_defined(self):
 | 
				
			||||||
            class A:
 | 
					            class A:
 | 
				
			||||||
                pass
 | 
					                pass
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class TestLRU(unittest.TestCase):
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    def test_lru(self):
 | 
					 | 
				
			||||||
        def orig(x, y):
 | 
					 | 
				
			||||||
            return 3*x+y
 | 
					 | 
				
			||||||
        f = functools.lru_cache(maxsize=20)(orig)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        domain = range(5)
 | 
					 | 
				
			||||||
        for i in range(1000):
 | 
					 | 
				
			||||||
            x, y = choice(domain), choice(domain)
 | 
					 | 
				
			||||||
            actual = f(x, y)
 | 
					 | 
				
			||||||
            expected = orig(x, y)
 | 
					 | 
				
			||||||
            self.assertEquals(actual, expected)
 | 
					 | 
				
			||||||
        self.assert_(f.hits > f.misses)
 | 
					 | 
				
			||||||
        self.assertEquals(f.hits + f.misses, 1000)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        f.clear()   # test clearing
 | 
					 | 
				
			||||||
        self.assertEqual(f.hits, 0)
 | 
					 | 
				
			||||||
        self.assertEqual(f.misses, 0)
 | 
					 | 
				
			||||||
        f(x, y)
 | 
					 | 
				
			||||||
        self.assertEqual(f.hits, 0)
 | 
					 | 
				
			||||||
        self.assertEqual(f.misses, 1)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    def test_lfu(self):
 | 
					 | 
				
			||||||
        def orig(x, y):
 | 
					 | 
				
			||||||
            return 3*x+y
 | 
					 | 
				
			||||||
        f = functools.lfu_cache(maxsize=20)(orig)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        domain = range(5)
 | 
					 | 
				
			||||||
        for i in range(1000):
 | 
					 | 
				
			||||||
            x, y = choice(domain), choice(domain)
 | 
					 | 
				
			||||||
            actual = f(x, y)
 | 
					 | 
				
			||||||
            expected = orig(x, y)
 | 
					 | 
				
			||||||
            self.assertEquals(actual, expected)
 | 
					 | 
				
			||||||
        self.assert_(f.hits > f.misses)
 | 
					 | 
				
			||||||
        self.assertEquals(f.hits + f.misses, 1000)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        f.clear()   # test clearing
 | 
					 | 
				
			||||||
        self.assertEqual(f.hits, 0)
 | 
					 | 
				
			||||||
        self.assertEqual(f.misses, 0)
 | 
					 | 
				
			||||||
        f(x, y)
 | 
					 | 
				
			||||||
        self.assertEqual(f.hits, 0)
 | 
					 | 
				
			||||||
        self.assertEqual(f.misses, 1)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
def test_main(verbose=None):
 | 
					def test_main(verbose=None):
 | 
				
			||||||
    test_classes = (
 | 
					    test_classes = (
 | 
				
			||||||
        TestPartial,
 | 
					        TestPartial,
 | 
				
			||||||
| 
						 | 
					@ -506,8 +461,7 @@ def test_main(verbose=None):
 | 
				
			||||||
        TestPythonPartial,
 | 
					        TestPythonPartial,
 | 
				
			||||||
        TestUpdateWrapper,
 | 
					        TestUpdateWrapper,
 | 
				
			||||||
        TestWraps,
 | 
					        TestWraps,
 | 
				
			||||||
        TestReduce,
 | 
					        TestReduce
 | 
				
			||||||
        TestLRU,
 | 
					 | 
				
			||||||
    )
 | 
					    )
 | 
				
			||||||
    support.run_unittest(*test_classes)
 | 
					    support.run_unittest(*test_classes)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -504,8 +504,6 @@ Library
 | 
				
			||||||
- Issue #4179: In pdb, allow "list ." as a command to return to the currently
 | 
					- Issue #4179: In pdb, allow "list ." as a command to return to the currently
 | 
				
			||||||
  debugged line.
 | 
					  debugged line.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
- Add lfu_cache() and lru_cache() decorators to the functools module.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
- Issue #4108: In urllib.robotparser, if there are multiple 'User-agent: *'
 | 
					- Issue #4108: In urllib.robotparser, if there are multiple 'User-agent: *'
 | 
				
			||||||
  entries, consider the first one.
 | 
					  entries, consider the first one.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue