源代码: Lib / functools.py
未完…
该模块用于高阶函数:作用于或返回其他函数的函数。通常,任何可调用对象都可以被视为用于此模块的函数。
@functools.lru_cache(maxsize=128, typed=False)
译者注:这里有一个简单的 例子
用一个memoizing callable来包装一个函数,它可以为最近的调用节省maxsize空间。当使用相同的参数定期调用或绑定昂贵的I/O
函数时,它可以节省时间。
由于字典用于缓存结果,因此函数的位置和关键字参数必须是可哈希的。
不同的参数模式可以被认为是具有单独的高速缓存条目的不同调用。例如,f(a=1, b=2)
和 f(b=2, a=1)
的关键字参数顺序不同,并且可能有两个单独的缓存条目。
如果将maxsize=None
,则禁用LRU(最近最少使用)功能,并且缓存可以无限制地增长。当maxsize是2的幂时,LRU功能表现最佳。
如果typed=True
,则将分别缓存不同类型的函数参数。例如,f(3)
和f(3.0)
将被视为产生截然不同的结果不同的调用。
为了帮助测量缓存的有效性并调整maxsize 参数,包装函数使用一个cache_info() 函数进行检测,该函数返回一个命名元组,显示hits,misses, maxsize,currsize
。在多线程环境中,hits
和misses
是近似值。
装饰器还提供cache_clear()功能用来清除或使缓存无效的。
可以通过__wrapped__
属性访问原始基础函数 。这对于内省,绕过缓存或使用不同的缓存重新包装函数非常有用。
当最近的调用是即将到来的调用的最佳预测时,LRU(最近最少使用的)缓存工作得最好(例如,新闻服务器上的最流行的文章往往每天更换)。缓存的大小限制可确保缓存不会增长,而不受长时间运行的进程(如Web服务器)的限制。
通常,只有在要重用以前计算的值时才应使用LRU高速缓存。因此,,需要在每次调用时创建不同的可变对象的函数,或者诸如time()或random()之类的不纯函数使用LRU是没什么效果的。
静态Web内容的LRU缓存示例:
@lru_cache(maxsize=32)
def get_pep(num):
'Retrieve text of a Python Enhancement Proposal'
resource = 'http://www.python.org/dev/peps/pep-%04d/' % num
try:
with urllib.request.urlopen(resource) as s:
return s.read()
except urllib.error.HTTPError:
return 'Not Found'
>>> for n in 8, 290, 308, 320, 8, 218, 320, 279, 289, 320, 9991:
... pep = get_pep(n)
... print(n, len(pep))
>>> get_pep.cache_info()
CacheInfo(hits=3, misses=8, maxsize=32, currsize=8)
使用高速缓存实现 动态编程 技术有效计算Fibonacci数的示例 :
@lru_cache(maxsize=None)
def fib(n):
if n < 2:
return n
return fib(n-1) + fib(n-2)
>>> [fib(n) for n in range(16)]
[0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233, 377, 610]
>>> fib.cache_info()
CacheInfo(hits=28, misses=16, maxsize=None, currsize=16)
版本3.2中的新功能。
版本3.3中已更改:添加了typed选项。
译者实例:
为了看出lru的效果,我们使用普通的fib函数和使用LRU的fib函数做对比:
def lru_test():
def fib(n):
if n < 2:
return n
return fib(n - 1) + fib(n - 2)
@lru_cache(None)
def fib2(n):
if n < 2:
return n
return fib2(n - 1) + fib2(n - 2)
import time
starttime = time.time()
print("before")
print(fib(34))
print("total",str(time.time() - starttime))
print("-".center(50,'*'))
starttime = time.time()
print("before")
print(fib2(450))
print(fib2.cache_info())
print("total", str(time.time() - starttime))
lru_test()
# 输出结果
before
5702887
total 1.9108920097351074
************************-*************************
before
4953967011875066473162524925231604047727791871346061001150551747313593851366517214899257280600
CacheInfo(hits=448, misses=451, maxsize=None, currsize=451)
total 0.0009984970092773438
可以看到,普通的fib求34的时候已经花费了1.9s,而经过LRU的fib在求450的时候只有不到0.001s的时间。