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
相关推荐
寻星探路2 小时前
【深度长文】万字攻克网络原理:从 HTTP 报文解构到 HTTPS 终极加密逻辑
java·开发语言·网络·python·http·ai·https
lly2024064 小时前
Bootstrap 警告框
开发语言
2601_949146534 小时前
C语言语音通知接口接入教程:如何使用C语言直接调用语音预警API
c语言·开发语言
陌上丨4 小时前
Redis的Key和Value的设计原则有哪些?
数据库·redis·缓存
曹牧4 小时前
Spring Boot:如何测试Java Controller中的POST请求?
java·开发语言
KYGALYX4 小时前
服务异步通信
开发语言·后端·微服务·ruby
zmzb01034 小时前
C++课后习题训练记录Day98
开发语言·c++
ValhallaCoder4 小时前
hot100-二叉树I
数据结构·python·算法·二叉树
猫头虎5 小时前
如何排查并解决项目启动时报错Error encountered while processing: java.io.IOException: closed 的问题
java·开发语言·jvm·spring boot·python·开源·maven
YUJIANYUE6 小时前
PHP纹路验证码
开发语言·php