functools高级工具:partial/partialmethod/cached_property/singledispatch/lru_cache
请详细说明functools模块中以下高级函数的用法和原理:
partial和partialmethod的区别cached_property(Python 3.8+)的实现机制lru_cache与cache(Python 3.9+)的性能差异singledispatch和singledispatchmethod实现多分派reduce在复杂累加场景中的使用
给出使用partialmethod冻结类方法的示例。
回答
我还是少年
partial vs partialmethod:
from functools import partial, partialmethod
# partial:冻结函数参数
import math
log_base2 = partial(math.log, base=2)
log_base2(16) # 4.0
# partialmethod:冻结类方法参数
class Window:
def __init__(self):
self.width = 800
self.height = 600
def resize(self, width, height):
self.width = width
self.height = height
double_width = partialmethod(resize, height=600) # 冻结height
win = Window()
win.double_width(1600) # width=1600, height=600
cached_property:
from functools import cached_property
class DataProcessor:
@cached_property
def heavy_computation(self):
time.sleep(5) # 第一次计算并缓存
return sum(range(10**7))
# 首次访问计算,后续直接返回缓存值
# 与@property不同:值存储在实例__dict__中,可被清除
lru_cache vs cache:
from functools import lru_cache, cache
@lru_cache(maxsize=128)
def fib(n):
return n if n < 2 else fib(n-1) + fib(n-2)
@cache # Python 3.9+,等价于 lru_cache(maxsize=None)
def factorial(n):
return n * factorial(n-1) if n else 1
cache无限大,适合参数空间有限的纯函数
singledispatch:
from functools import singledispatch
@singledispatch
def serialize(obj):
raise TypeError(f'Unsupported type: {type(obj)}')
@serialize.register(int)
def _(obj):
return str(obj)
@serialize.register(list)
def _(obj):
return ','.join(str(x) for x in obj)
@serialize.register(dict)
def _(obj):
import json
return json.dumps(obj)
reduce高级用法:实现像itertools.accumulate一样累加但返回最终值,或实现min/max:
from functools import reduce
reduce(lambda a, b: a if a > b else b, [3, 1, 4, 1, 5, 9]) # 9