Python高级用法:装饰器用于缓存

缓存装饰器

缓存装饰器与参数检查十分相似,不过它重点是关注那些内部状态不会影响输出的函数。每组参数都可以链接到唯一的结果。这种编程风格是函数式编程的特点,当输入值有限时可以使用。

因此,缓存装饰器可以将输出与计算它所需要的参数放在一起,并在后续的调用中直接返回它。这种行为被称为memoizing。

例子

我们下面创建一个使用装饰器缓存技术,实现记录在一定时间内函数是否被调用的例子,来解释装饰器用于缓存的用法。

准备工作

首先我们准备引入相关的包,time用于获取当前时间,hashlib用于转换成哈希值,pickle用于将多个参数打包成一个对象,cache变量代表的是对函数返回值和时间的缓存。

python 复制代码
import time
import hashlib
import pickle

cache = {}

依赖函数

python 复制代码
def is_obsolete(entry, duration):
    return time.time() - entry['time'] > duration


def compute_key(function, args, kw):
    key = pickle.dumps((function.__name__, args, kw))
    return hashlib.sha1(key).hexdigest()

is_obsolete函数是用来比较上次函数访问时间(entry'time',entry是一个字典,entry'time'存储的就是上次访问的时间)与当前时间(time.time())的间隔是否大于指定间隔(duration)的函数。

compute_key函数将传入的function,args,kw打包并转换成二进制形式,作为函数与参数对应的唯一标识。

构建修饰器

python 复制代码
def memoize(duration=10):
    def _memoize(function):
        def __memoize(*args, **kw):
            key = compute_key(function, args, kw)
            # 是否已经拥有它了?
            if (key in cache and
                    not is_obsolete(cache[key], duration)):
                print('we got a winner')
                return cache[key]['value']
            # 计算
            result = function(*args, **kw)
            # 保存结果
            cache[key] = {
                'value': result,
                'time': time.time()
            }
            return result
        return __memoize
    return _memoize

在__memoize函数中,先使用compute_key函数获取十六进制的哈希值,作为唯一关键词。然后查询是否存在于缓存中(cache)并且时间是否满足条件,如果均满足则直接返回上次的运行结果。否则重新计算结果并将结果存入缓存(cache)后返回。

测试

我们首先创建一个实现加法运算的函数

python 复制代码
@memoize()
def add(a, b):
    # 如果在执行这个计算时计算机过热
    # 请考虑中止程序
    return a + b

如果我们用以下代码测试

python 复制代码
print(add(1, 2))
print(add(1, 2))
print(add(2, 2))

得到的运行结果如下:

复制代码
3
we got a winner
3
4

第二次调用add(1, 2)时因为前面已经调用过了,所以就直接给出提示返回结果,而add(2, 2)是一个新的参数的运算,所以进行了再次重复的运算。

下面我们来看一下如果超时会有怎样的结果,由于默认的menoize参数是10,所以我们这里改成1

python 复制代码
@memoize(1) # 1秒后令缓存失效
def add(a, b):
    return a + b
    
print(add(2, 3))
time.sleep(2)
print(add(2, 3))

我们使用time.sleep沉睡两秒

运行结果是

复制代码
5
5
相关推荐
代龙涛28 分钟前
WordPress page.php 页面模板与自定义模板使用方法
android·开发语言·php
bigfootyazi36 分钟前
python爬虫-基本库-urllib库(常用速查)
开发语言·爬虫·python
瑶总迷弟1 小时前
使用 mis-tei 在昇腾310P上部署 bge-m3模型
pytorch·python·华为·语言模型·自然语言处理·cnn·unix
belong_my_offer1 小时前
认识到精通函数
开发语言·python
guygg881 小时前
最大相关-最小冗余(mRMR)特征选择 MATLAB 实现
开发语言·matlab
yurenpai(27届找实习中)1 小时前
redis_点评(21.好友关注——关注、取关功能实现;共同关注功能实现)
数据库·redis·缓存
郭涤生2 小时前
C++ 高性能编程最佳实践清单
开发语言·c++
烛衔溟2 小时前
TypeScript 类的静态成员与静态方法
开发语言·javascript·typescript
Nile2 小时前
解密Palantir系列一:4. Ontology 不是哲学
开发语言·前端·javascript
Trouvaille ~2 小时前
【Redis篇】Set 与 Zset:集合运算与排行榜的终极武器
数据库·redis·缓存·set·跳表·后端开发·zset