python--functools模块

reduce
  • reduce顾名思义就是减少
  • reduce(function,seq[,initial])
  • 可迭代对象不能为空;初始值没有就从可迭代对象中取一个元素
from functools import reduce
num=[1,2,3,4,5]
print(sum(num))
print(reduce(lambda val,x:val + x),num)#相当于sum函数
print(reduce(lambda val,x:val * x),num)#相当于num的阶乘
partial–偏函数
  • 把部分参数固定下来,相当于为部分参数添加了一个固定的默认值,形成一个新的函数并返回
  • 从partial生成返回的新函数,是对原函数的封装
from functools import partial
def add(x,y):
	return x + y
newadd=partial(add,4)
print(newadd(5))
print(newadd(5,y=10))#TypeError: add() got multiple values for argument 'y'
print(newadd(x=5,y=10))#add() got multiple values for argument 'x'

分析:
partial函数相当于提前为部分参数添加默认值,所以当调用partial函数给定一个位置参数传参时(partial(add,4)),这个值会给第一个参数(x),返回的新函数为newadd(x=4,y)

partial函数的本质(伪代码)

def partial(func,*args,**keywords):
	def newfunc(*fargs,**fkeywords):#包装函数
		newkeywords=keywords.copy()
		newkeywords.update(fkeywords)
		return func(*(args + fargs),**newkeywords)
	newfunc.func=func#保留原函数
	newfunc.args=args#保留原位置参数
	newfunc.keywords=keywords#保留原关键字参数
	return newfunc
lru_cache

@functools.lrucache(maxsize=128,typed=False)

  • Least-recently-used装饰器,lru最近最少使用,cache缓存;
  • 如果maxsize设置为None,则禁用lru功能,并且缓存可以无限制增长,当maxsize是2的幂时,LRU功能执行最好;
  • 如果typed设置为True,则不同类型的函数参数将单独缓存,例如:fn(5)和fn(5.0),将被视为不同结果的不同调用。

举例:

from functools import lru_cache
import time
@lru_cache()
def add(x,y):
    time.sleep(2)
    return x + y

add(4,5)
add(4.0,5)
add(5,4)
add(4,y=5)

总结:

  • lru_cache是通过字典把被装饰函数的调用之和返回值储存起来;
  • 使用前提:同样的参数一定得到同样的结果,函数执行时间长且需要执行多次;
  • 本质是函数调用的参数=>返回值;
  • 缺点:不支持缓存过期,key无法过期,清除;不支持分布式,单机缓存
自定义一个cache函数,实现过期清除key的功能
import inspect
from functools import wraps
import  time
import datetime

def cache(fn):
     local_cache = {} # 对不同函数名是不同的cache
     @wraps(fn)
     def wrapper(*args, **kwargs):
         def _clear_expire():
             # 清除缓存:注意:在对字典迭代的时候,是不能删除的!
             expire_keys = []
             # for k, v  in local_cache.items(): # {(('x', 4), ('y', 5)): (9, 1535638337.355427)}
             #     ret, stamp = v
             # 等价
             for k,(_,stamp) in local_cache.items():
                 if datetime.datetime.now().timestamp() - stamp > 5:
                     expire_keys.append(k)
             for k in expire_keys:
                 local_cache.pop(k)
             # 每次都要遍历,最好用线程,用的时候清除
         def _make_key(args,kwargs):
             sig = inspect.signature(fn)  # 获取签名 (x=4, y=5)
             params = sig.parameters  # 获取参数字典,有序的 OrderedDict([('x', <Parameter "x=4">), ('y', <Parameter "y=5">)])
             values = list(params.values())  # 有序的 [<Parameter "x=4">, <Parameter "y=5">]
             keys = list(params.keys())  # ['x', 'y']
             param_dic = {}  # c参数字典
             # 位置传参
             for k, v in enumerate(args):
                 param_dic[keys[k]] = v
             param_dic.update(zip(params.keys(), args))  # 二元组,放到字典中,形成 k-v对
             # 关键字传参
             param_dic.update(kwargs)  # 关键字参数,放到字典中
             # 缺省值
             for k, v in params.items():  # OrderedDict([('x', <Parameter "x=4">), ('y', <Parameter "y=5">)])
                 if k not in param_dic:
                     param_dic[k] = v.default
             key = tuple(sorted(param_dic.items()))  # sorted生成列表,不能做key,所以tuple一下(key必须是可hash的,因为要用字典) (('x', 4), ('y', 5))
             return key

         _clear_expire()

         key = _make_key(args,kwargs)

         if key not in local_cache.keys():
             local_cache[key] = fn(*args, **kwargs), datetime.datetime.now().timestamp() # 放到二元组中,记录的是缓存的时间
             # 形成一个 {key:stamp}的字典
             #如果说到点清除,最好写结束时间,到点清除,记录一个未来时间

         print(local_cache) # {(('x', 4), ('y', 5)): (9, 1535638337.355427)}
         # print(local_cache[key])
         return local_cache[key]

     return wrapper

@cache
def add(x,y):
    return x+y

add(4,5)
time.sleep(5)
add(4,y=5)
time.sleep(5)
add(x=4,y=5)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值