Python装饰器练习 ---实现一个缓存cache+可过期被清除的功能

实现一个cache 缓存,实现可过期被清除的功能

简化设计,函数的形参定义不包含可变位置参数、可变关键词参数和keyword-only参数
可以不考虑缓存大小,也不用考虑缓存满了之后的换出问题

编写的函数,满足:

def add(x=4, y=5):
	time.sleep(3)
	return x + y
以下6种,可以认为是同一种调用
print(1, add(4,5))
print(2, add(4))
print(3, add(y=5))
print(4, add(x=4,y=5))
print(5, add(y=5,x=4))
print(6, add())

分析:

数据类型的选择

缓存的应用场景,是有数据需要频繁查询,且每次查询都需要大量计算或者等待时间之后才能返回结果的情况,使
用缓存来提高查询速度,用内存空间换取查询、加载的时间。

cache应该选用什么数据结构?
便于查询的,且能快速获得数据的数据结构。
每次查询的时候,只要输入一致,就应该得到同样的结果(顺序也一致,例如减法函数,参数顺序不一致,结果不
一样)
基于上面的分析,此数据结构应该是字典。
通过一个key,对应一个value。
key是参数列表组成的结构,value是函数返回值。难点在于key如何处理。
key的存储
key必须是hashable
key能接受到位置参数和关键字参数传参。
位置参数是被收集在一个tuple中的,本身就有顺序。
关键字参数被收集在一个字典中,本身无序,这会带来一个问题,传参的顺序未必是字典中保存的顺序。如何解
决?

  1. OrderedDict行吗?可以,它可以记录顺序。
  2. 不用OrderedDict行吗?可以,用一个tuple保存排过序的字典的item的kv对。

key的异同
什么才算是相同的key呢?

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

定义一个加法函数,那么传参方式就应该有以下4种:
1. add(4, 5)
2. add(4, y=5)
3. add(y=5, x=4)
4. add(x=4, y=5)

上面4种,可以有下面几种理解:
第一种:1、2、3、4都不同。
第二种:3和4相同,1、2和3都不同。
第三种:1、2、3、4全部相同。
lru_cache实现了第一种,从源码中可以看出单独的处理了位置参数和关键字参数。
但是函数定义为def add(4, y=5),使用了默认值,如何理解add(4, 5)和add(4)是否一样呢?
如果认为一样,那么lru_cache无能为力。
就需要使用inspect来自己实现算法。
key的要求
key必须是hashable。
由于key是所有实参组合而成,而且最好要作为key的,key一定要可以hash,但是如果key有不可hash类型数据,
就无法完成。
lru_cache就不可以,我们也很难实现,所以不能在实参中出现不可hash类型。
key算法设计
inspect模块获取函数签名后,取parameters,这是一个有序字典,会保存所有参数的信息。
构建一个字典params_dict,按照位置顺序从args中依次对应参数名和传入的实参,组成kv对,存入params_dict
中。
kwargs所有值update到params_dict中。
如果使用了缺省值的参数,不会出现在实参params_dict中,会出现在签名的parameters中,缺省值也在函数定义
中。
调用的方式
普通的函数调用可以,但是过于明显,最好类似lru_cache的方式,让调用者无察觉的使用缓存。
构建装饰器函数。

代码实现:

首先我们使用python自带的lru_cache模块进行编写:

#系统自带的lru_cache 模块 
import functools
import time
@functools.lru_cache()
def add(x=4,y=5):
    time.sleep(2)
    return x+y 
print(1, add(4,5))
print(2, add(4))
print(3, add(y=5))
print(4, add(x=4,y=5))
print(5, add(y=5,x=4))
print(6, add())

其运行的结果如下图所示:

  • 2
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值