Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
C
cpython
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
Kirill Smelkov
cpython
Commits
2e7346ac
Commit
2e7346ac
authored
Jul 31, 2010
by
Georg Brandl
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Re-commit r83327 now that the release is done.
parent
4f2a0a88
Changes
4
Hide whitespace changes
Inline
Side-by-side
Showing
4 changed files
with
193 additions
and
2 deletions
+193
-2
Doc/library/functools.rst
Doc/library/functools.rst
+51
-0
Lib/functools.py
Lib/functools.py
+93
-1
Lib/test/test_functools.py
Lib/test/test_functools.py
+47
-1
Misc/NEWS
Misc/NEWS
+2
-0
No files found.
Doc/library/functools.rst
View file @
2e7346ac
...
@@ -37,6 +37,57 @@ The :mod:`functools` module defines the following functions:
...
@@ -37,6 +37,57 @@ 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
...
...
Lib/functools.py
View file @
2e7346ac
...
@@ -4,10 +4,17 @@
...
@@ -4,10 +4,17 @@
# 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>
# Copyright (C) 2006 Python Software Foundation.
# and Raymond Hettinger <python at rcn.com>
# 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
...
@@ -97,3 +104,88 @@ def cmp_to_key(mycmp):
...
@@ -97,3 +104,88 @@ def cmp_to_key(mycmp):
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
Lib/test/test_functools.py
View file @
2e7346ac
...
@@ -4,6 +4,7 @@ import unittest
...
@@ -4,6 +4,7 @@ import unittest
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
):
...
@@ -454,6 +455,50 @@ class TestTotalOrdering(unittest.TestCase):
...
@@ -454,6 +455,50 @@ class TestTotalOrdering(unittest.TestCase):
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
,
...
@@ -461,7 +506,8 @@ def test_main(verbose=None):
...
@@ -461,7 +506,8 @@ def test_main(verbose=None):
TestPythonPartial
,
TestPythonPartial
,
TestUpdateWrapper
,
TestUpdateWrapper
,
TestWraps
,
TestWraps
,
TestReduce
TestReduce
,
TestLRU
,
)
)
support
.
run_unittest
(
*
test_classes
)
support
.
run_unittest
(
*
test_classes
)
...
...
Misc/NEWS
View file @
2e7346ac
...
@@ -516,6 +516,8 @@ Library
...
@@ -516,6 +516,8 @@ 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.
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment