3、内置模块functools
...About 3 min
3、内置模块functools
一、内置lru缓存
LRU是一种常用的缓存算法,即最近最少使用,如果一个数据在最近一段时间没有被访问到,那么在将来它被访问的可能性也很小, LRU算法选择将最近最少使用的数据淘汰,保留那些经常被命中的数据。****
import time
from functools import lru_cache
@lru_cache() # 测试无缓存时将本行注释掉
def fib_memoization(number: int) -> int:
if number == 0: return 0
if number == 1: return 1
return fib_memoization(number-1) + fib_memoization(number-2)
start = time.time()
res = fib_memoization(33)
print(res)
print(f'耗时: {time.time() - start}s')
functools.lru_cache参数说明
lru_cache装饰器定义如下
def lru_cache(maxsize=128, typed=False):
pass
只有连个参数,第一个参数规定缓存的数量,第二个参数如果设置为True,则严格检查被装饰函数的参数类型,默认为False
from functools import lru_cache
@lru_cache(typed=False)
def add(x, y):
print('add')
return x + y
print(add(3, 4))
print(add(3, 4.0))
第二次调用add函数时参数是4.0, 如果你认为这种情况可以使用缓存命中上一次3+4的结果,就将typed设置为False,如果你严格要求只有函数的参数完全一致时才能命中,那么将typed设置为True
二、wraps函数
自省信息丢失
函数被装饰以后,一些原本属于自己的自省信息会丢失,先来看装饰前的样子
def test(sleep_time):
"""
测试装饰器
:param sleep_time:
:return:
"""
time.sleep(sleep_time)
print(test.__name__)
print(test.__doc__)
执行输出结果
test
测试装饰器
:param sleep_time:
:return:
test是函数的名字,__doc__是函数的注释说明
但在被普通的装饰器装饰以后,这些信息就会丢失
import time
def cost(func):
def warpper(*args, **kwargs):
t1 = time.time()
res = func(*args, **kwargs)
t2 = time.time()
print(func.__name__ + "执行耗时" + str(t2-t1))
return res
return warpper
@cost
def test(sleep_time):
"""
测试装饰器
:param sleep_time:
:return:
"""
time.sleep(sleep_time)
print(test.__name__)
print(test.__doc__)
程序输出结果
warpper
None
这是我们所不希望看到的
修复自省信息
wraps可以防止被装饰的函数丢失自己的自省信息,只需要增加@wraps(func)即可
import time
from functools import wraps
def cost(func):
@wraps(func)
def warpper(*args, **kwargs):
t1 = time.time()
res = func(*args, **kwargs)
t2 = time.time()
print(func.__name__ + "执行耗时" + str(t2-t1))
return res
return warpper
@cost
def test(sleep_time):
"""
测试装饰器
:param sleep_time:
:return:
"""
time.sleep(sleep_time)
print(test.__name__)
print(test.__doc__)
三、偏函数partial
偏函数partial是functools 模块里提供的一个函数。和装饰器对比来理解,装饰器改变了一个函数的行为,而偏函数不能改变一个函数的行为。偏函数只能根据已有的函数生成一个新的函数,这个新的函数完成已有函数相同的功能,但是,这个新的函数的部分参数已被偏函数确定下来
常规实现
为了便于理解,我们构造一个使用场景,假设我们的程序要在dest目录下新建一些文件夹,那么常见的实现功能代码如下
import os
from os import mkdir
mkdir(os.path.join('./dest', 'dir1'))
mkdir(os.path.join('./dest', 'dir2'))
mkdir(os.path.join('./dest', 'dir3'))
功能很简单,代码很简洁,但是有个小小的不如意之处,每次都是在dest目录下新建文件夹,既然它这么固定,是不是可以不用传递dest参数呢?
偏函数实现
import os
from os import mkdir
from functools import partial
dest_join = partial(os.path.join, './dest')
mkdir(dest_join('dir1'))
mkdir(dest_join('dir2'))
mkdir(dest_join('dir3'))
Powered by Waline v2.15.8