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
相关推荐
weixin_4723394629 分钟前
高效处理大体积Excel文件的Java技术方案解析
java·开发语言·excel
枯萎穿心攻击1 小时前
响应式编程入门教程第二节:构建 ObservableProperty<T> — 封装 ReactiveProperty 的高级用法
开发语言·unity·c#·游戏引擎
Eiceblue2 小时前
【免费.NET方案】CSV到PDF与DataTable的快速转换
开发语言·pdf·c#·.net
m0_555762903 小时前
Matlab 频谱分析 (Spectral Analysis)
开发语言·matlab
浪裡遊4 小时前
React Hooks全面解析:从基础到高级的实用指南
开发语言·前端·javascript·react.js·node.js·ecmascript·php
Hello.Reader5 小时前
Redis 延迟排查与优化全攻略
数据库·redis·缓存
烛阴5 小时前
简单入门Python装饰器
前端·python
lzb_kkk5 小时前
【C++】C++四种类型转换操作符详解
开发语言·c++·windows·1024程序员节
好开心啊没烦恼5 小时前
Python 数据分析:numpy,说人话,说说数组维度。听故事学知识点怎么这么容易?
开发语言·人工智能·python·数据挖掘·数据分析·numpy
面朝大海,春不暖,花不开5 小时前
使用 Python 实现 ETL 流程:从文本文件提取到数据处理的全面指南
python·etl·原型模式