名称 | 解释 |
---|---|
lru_cache | 缓存函数执行的结果, 注意被装饰的函数, 只接受不可变类型的传参 |
partial | 在不改变原函数本身的情况下, 固定原函数的某些参数, 生成一个新的函数 |
wraps | 将被装饰器装饰过的函数的一些属性, 也copy到闭包环境中 |
update_wrapper | 同wraps |
singledispatch | 将函数绑定, 通过传参数类型不同, 执行不同的函数 |
1.lru_cache
1.1 使用场景
当某个函数操作耗时时间较长,但每次调用时传入的参数相同时,可以将结果放置到缓存中,再次执行时,可以跳过执行函数,直接在缓存中获取结果
1.2 代码原理
from functools import lru_cache
# maxsize 为缓存数量, 一般为2的幂性能最佳, typed表示相同参数的不同类型参数,算作不同的缓存
@lru_cache(maxsize=1, typed=True)
def func(var):
print(var + 1)
return var
print(func(1))
print(func(1))
# 查看缓存
print(func.cache_info())
print(func(2))
print(func.cache_info())
# 清空缓存
func.cache_clear()
print(func.cache_info())
# 以上代码执行结果为:
# 第一次调用时,执行了func函数中的print, 第二次传入同样的参数时, 没有执行print,而是从缓存中直接获取结果
2
1
1
# hits为缓存命中次数, misses为缓存数量
CacheInfo(hits=1, misses=1, maxsize=1, currsize=1)
3
2
CacheInfo(hits=1, misses=2, maxsize=1, currsize=1)
# 清空缓存后, 为0
CacheInfo(hits=0, misses=0, maxsize=1, currsize=0)
2.partial
2.1 使用场景
当我们频繁调用某个函数时,其中函数的某些参数是已知的固定值, 如果将这些参数写成 var=xxx 的默认参数形式时的缺陷是, 每次增删改参数时都要改动函数本身,不够灵活
2.2 代码原理
# 当我们想要实现一个功能: 每次计算某些数字 + 100 的结果
# 第一种做法:该写法导致每次传入100,代码冗余
def add(*args):
return sum(args)
print(add(1, 2, 3) + 100)
print(add(5, 5, 5) + 100)
# 第二种做法: 该写法导致想要计算不同结果时 要修改函数本身, 不够灵活
def add(*args):
# 对传入的数值相加后,再加上100返回
return sum(args) + 100
print(add(1, 2, 3)) # 106
print(add(5, 5, 5)) # 115
# 第三种做法: 该写法导致函数参数固定, 不够灵活
def add(*args, num=100)
return sum(args) + num
print(add(1, 2, 3))
print(add(5, 5, 5))
# 最后使用partial改写该函数
from functools import partial
def add(*args)
return sum(args)
p1 = partial(add, 100) # 将100提前传入函数
p1((1, 2, 3))
p2 = partial(add, 200) # 将200提前传入函数, 体现了函数的灵活性
p2((1, 2, 3))
2.3 使用注意事项
from functools import partial
def func(a, b, c, d):
print(a, b, c, d)
func(1, 2, 3, 4) # 普通传参
p1 = partial(func, 1, 2, 3, 4)
p1() # 1.不需要传入参数, 因为已经提前固定
p2 = partial(func, 1, 2)
p2(3, 4) # 2.提前固定了a, b参数,但是c, d参数需要传参
p3 = partial(func, b=2, d=4)
p3(1, c=3)
p3(a=1, c=3) # 3.如果关键字参数不是连续的, 则调用函数时, 前面的参数使用位置参数, 后面的参数使用关键字参数,或者同时使用关键字参数
3.wraps
3.1 使用场景
当函数被装饰器装饰时, 该函数的属性会发生改变, 不再表示原函数, 如果想要展示原函数的属性,则需要使用wrapper
3.2 代码原理
from functools import wraps
def wrapper_func(func):
@wraps(func) # 这里使用wraps, 将原func函数的属性继承过来
def wrapper_func_core(*args, **kwargs):
"""这里是wrapper_func_core函数备注"""
print("这里是装饰器对func函数新添加的 打印功能")
return func()
return wrapper_func_core
@wrapper_func
def func():
"""这里是func的函数备注"""
pass
print(func.__doc__) # 如果没有wraps, 则将显示wrapper_func_core备注, 而不是func备注
print(func.__name__)
print(func.__module__)
print(func.__dict__)
4. update_wrapper
同wraps作用相同, 但是wraps更简便
5.singledispatch
from functools import singledispatch
@singledispatch
def show(var):
print(f"show函数{var}")
@show.register(str)
def f_test(text):
print(f"text函数{text}")
@show.register(int)
def f_int(n):
print(f"inte函数{n}")
@show.register(list)
def f_list(li):
print(f"list函数{li}")
show([]) # 这里调用show函数时, 会根据传参的类型, 执行f_list函数
show({}) # 如果show函数没有绑定 参数类型的函数, 则执行show函数本身
f_test(11) # 被show函数绑定的函数, 也可以正常使用