functools 提供了 11个函数:
- cached_property()
- cmp_to_key()
- lru_cache()
- partial()
- partialmethod()
- reduce()
- singledispatch()
- singledispatchmethod()
- total_ordering()
- update_wrapper()
- wraps()
@cached_property - 缓存实例方法
它的目的是将类的一个方法转换为一个属性,该属性的值只计算一次,然后被缓存为实例生命周期中的一个普通属性。其行为与内置的@property 装饰器[2]非常相似,只是增加了缓存过程。让我们来看一下来自Python文档中的例子:
1.将方法转换为缓存属性,只计算一次,然后缓存'
@ft.cached_property
class Dateset:
def __init__(self, sequence_of_numbers):
self._data = sequence_of_numbers
'将方法转换为缓存属性,只计算一次,然后缓存'
@ft.cached_property
def stdev(self): # 计算标准差
return statistics.stdev(self._data)
@ft.cached_property
def variance(self): # 计算方差
return statistics.variance(self._data)
2.一个转换函数
cmp_to_key()
理解比较函数和键函数之间的区别
比较函数:第一个数相比第一个数; 0:等于, 1:大于,-1:小于
键函数:一个可调用的对象,接受一个参数并返回另一个用作排序键的值
函数通常会被提供给像sort()、min()和max()之类的内置函数。
cmp_to_key()会将一个比较函数转换为一个键函数
3. @lru_cache() - 通过缓存增加代码性能,是一个装饰器,
它用一个记忆化的可调用对象来包装一个函数,这个可调用对象可以保存最近的maxsize次调用(默认值:128)。
@ft.lru_cache(maxsize=32) # 缓存大小设置为32
def get_pep(number: int)->str: # (number:int)->str: 等价于(number)
resource= f"http://www.python.org/dev/peps/pep-{number:04d}/" # number:04d 取4位格式
print(resource)
try:
with request.urlopen(resource) as s:
return s.read()
except error.HTTPError:
return "Not Found"
list_of_peps = [8,290,308,320,8,218,320,279,289,320,9991]
# 总共11条,会调用8次,另外3次调用缓存值
for i in list_of_peps:
pep= get_pep(i) # i相同时不会重复执行,直接输出结果,8(2次),320(3次)
print(i,len(pep))
print(get_pep.cache_info())
# 使用了3次缓存值,而不是再调用
#CacheInfo(hits=3, misses=8, maxsize=32, currsize=8)
http://www.python.org/dev/peps/pep-0008/
8 103972
http://www.python.org/dev/peps/pep-0290/
290 60728
http://www.python.org/dev/peps/pep-0308/
308 57934
http://www.python.org/dev/peps/pep-0320/
320 50512
8 103972
http://www.python.org/dev/peps/pep-0218/
218 47756
320 50512
http://www.python.org/dev/peps/pep-0279/
279 49514
http://www.python.org/dev/peps/pep-0289/
289 51843
320 50512
http://www.python.org/dev/peps/pep-9991/
9991 9
CacheInfo(hits=3, misses=8, maxsize=32, currsize=8)
4. @total_ordering - 通过使用装饰器来减少代码行数
@ft.total_ordering
class Pythonista:
firstname:str
lastname:str
def __init__(self, firstname:str,lastname:str)->None:
self.firstname = firstname
self.lastname = lastname
def __eq__(self, other:object)->bool:
if not isinstance(other, Pythonista):
return NotImplemented
return ((self.lastname.lower(),self.firstname.lower())==(other.lastname.lower(),other.firstname.lower()))
def __lt__(self, other:object)->bool:
if not isinstance(other, Pythonista):
return NotImplemented
return ((self.lastname.lower(),self.firstname.lower())<(other.lastname.lower(),other.firstname.lower()))
guido= Pythonista('Guido','van Rossum')
brett= Pythonista("Brett","Cannon")
print(guido>brett) #True
5.reduce 基于多个值计算单个值
# ft.reduce 基于多个值计算单个值
import operator as opt
iterable=[i for i in range(1,6)]
# opt.add,opt.mul 只能计算两个数的和和乘积
result= ft.reduce(opt.add, iterable)
print(result) # 计算之和
result= ft.reduce(opt.mul, iterable)
print(result) # 计算乘积
[email protected] - 函数重载
# @singledispatch - 函数重载
#@singledispatch装饰器会将一个函数转换为一个
# 单分派泛函数。在@singledispatch的情况下,
# 分派发生在第一个参数的类型上。
# 加载函数上给函数提供注册功能
@ft.singledispatch
def mul(a,b):
return a*b
@mul.register
def _(a:str, b:str):
return a+b
print(mul(1,2))
print(mul('1','2'))
[email protected] - 方法重载
# @singledispatchmethod - 方法重载
class Negator:
@ft.singledispatchmethod
def neg(self,arg):
raise NotImplementedError("Cannot negate a")
@neg.register
def _(self,arg:int):
return -arg
@neg.register
def _(self,arg:bool):
return not arg
print(Negator().neg(5))
print(Negator().neg(False))
#print(Negator().neg("hello"))
8.wraps 打印func的备注信息
参考博客:https://mp.weixin.qq.com/s?src=11×tamp=1631928439&ver=3321&signature=MuIgp-dOGZb4kxlLjUoi8kTaIEfcspwwaVVTrsJraIX2WmWp346x58pznYwp*9x2deiG6z1jLtRGKQQLq7N8JtTjJ*O0Xxr0jkCASApwqTIf*jk9VZ5JwzFMf3KrwQ4D&new=1