Python 如何手动编写一个自己的LRU缓存装饰器的方法实现

LRU缓存算法,指的是近期最少使用算法,大体逻辑就是淘汰最长时间没有用的那个缓存,这里我们使用有序字典,来实现自己的LRU缓存算法,并将其包装成一个装饰器。

1、首先创建一个my_cache.py文件 编写自己我们自己的LRU缓存算法,代码如下:

import time
from collections import OrderedDict

'''
基于LRU,近期最少用缓存算法写的装饰器。
'''

class LRUCacheDict:
    def __init__(self, max_size=1024, expiration=60):
        self.max_size = max_size
        self.expiration = expiration

        self._cache = {}
        self._access_records = OrderedDict()  # 记录访问时间
        self._expire_records = OrderedDict()  # 记录失效时间

    def __setitem__(self, key, value):  # 设置缓存
        now = int(time.time())
        self.__delete__(key)  # 删除原有使用该Key的所有缓存

        self._cache[key] = value
        self._access_records = now  # 设置访问时间
        self._expire_records = now + self.expiration  # 设置过期时间
        self.cleanup()

    def __getitem__(self, key):  # 更新缓存
        now = int(time.time())
        del self._access_records[key]  # 删除原有的访问时按
        self._access_records[key] = now
        self.cleanup()

    def __contains__(self, key):  # 这个是字典默认调用key的方法
        self.cleanup()
        return key in self._cache

    def __delete__(self, key):
        if key in self._cache:
            del self._cache[key]  # 删除缓存
            del self._access_records[key]  # 删除访问时间
            del self._expire_records[key]  # 删除过期时间

    def cleanup(self):  # 用于去掉无效(超过大小)和过期的缓存
        if self._expire_records is None:
            return None

        pending_delete_keys = []
        now = int(time.time())
        for k, v in self._expire_records.items():  # 判断缓存是否失效
            if v < now:
                pending_delete_keys.append(k)

        for del_k in pending_delete_keys:
            self.__delete__(del_k)

        while len(self._cache) > self.max_size:  # 判断缓存是否超过长度
            for k in self._access_records.keys():  # LRU 是在这里实现的,如果缓存用的最少,那么它存入在有序字典中的位置也就最前
                self.__delete__(k)
                break

代码逻辑其实很简单,上面的注释已经很详细了,不懂的话多看几次。这里实现LRU逻辑的其实是有序字典OrderedDict,你最先存入的值就会存在字典的最前面。当一个值使用时候,我们会重新储存过期时间,导致被经常使用的缓存,会存在字典的后面。而一但缓存的内容长度超过限制时候,这里会调用有序字典最前面的key(也即是近期相对用的最少的),并删除对应的内容,以达到LRU的逻辑。

2、在将我们写好的算法改成装饰器:

from functools import wraps
from my_cache import LRUCacheDict

def lru_cache(max_size=1024, expiration=60, types='LRU'):
    if types == 'lru' or types == 'LRU':
        my_cache = LRUCacheDict(max_size=max_size, expiration=expiration)

    def wrapper(func):
        @wraps(func)
        def inner(*args, **kwargs):
            key = repr(*args, **kwargs)
            try:
                result = my_cache[key]
            except KeyError:
                result = func(*args, **kwargs)
                my_cache[key] = result
            return result

        return inner

    return wrapper

这里需要解释的是直接使用 my_cache[key],这个类似字典的方法,实际上是调用了 LRUCacheDict 中的 __contations__方法,这也是字典中实现通过key取值的方法。这个装饰器里,我加入了types的参数,你们可以根据需求,实现不同的缓存算法,丰富这个装饰器的功能,而lru缓存本身,其实已经是python的标准库了,可以引入functools.lru_cache来调用。

到此这篇关于Python 如何手动编写一个自己的LRU缓存装饰器的方法实现的文章就介绍到这了,更多相关Python LRU缓存装饰器内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • python实现LRU热点缓存及原理

    LRU LRU(Least recently used,最近最少使用)算法根据数据的历史访问记录来进行淘汰数据,其核心思想是"如果数据最近被访问过,那么将来被访问的几率也更高". 基于列表+Hash的LRU算法实现. 访问某个热点时,先将其从原来的位置删除,再将其插入列表的表头 为使读取及删除操作的时间复杂度为O(1),使用hash存储热点的信息的键值 class LRUCaceh(): def __init__(self, size=5): ''' 默认队列的长度为5 使用列表来维护

  • python自带缓存lru_cache用法及扩展的使用

    目录 1. lru_cache的使用 1.1 参数详解 1.2 基本用法 1.3 进阶用法 2. functiontools.wrap装饰器对lru_cache的影响 2.1 多个装饰器装饰同一函数时的执行顺序 2.2 functiontools.wrap原理 2.3 使用wrap装饰器前后的变化 3. 自制简易的my_cache 3.1 lru_cache提供的功能 3.2 cache的核心部件 3.3 my_cache的实现 4. lru_cache缓存和redis缓存的区别 5. 总结 本

  • 工程师必须了解的LRU缓存淘汰算法以及python实现过程

    大家好,欢迎大家来到算法数据结构专题,今天我们和大家聊一个非常常用的算法,叫做LRU. LRU的英文全称是Least Recently Used,也即最不经常使用.我们看着好像挺迷糊的,其实这个含义要结合缓存一起使用.对于工程而言,缓存是非常非常重要的机制,尤其是在当下的互联网应用环境当中,起到的作用非常重要.为了便于大家更好地理解,我们从缓存的机制开始说起. 缓存 缓存的英文是cache,最早其实指的是用于CPU和主存数据交互的.早年这块存储被称为高速缓存,最近已经听不到这个词了,不知道是不是

  • Python 如何手动编写一个自己的LRU缓存装饰器的方法实现

    LRU缓存算法,指的是近期最少使用算法,大体逻辑就是淘汰最长时间没有用的那个缓存,这里我们使用有序字典,来实现自己的LRU缓存算法,并将其包装成一个装饰器. 1.首先创建一个my_cache.py文件 编写自己我们自己的LRU缓存算法,代码如下: import time from collections import OrderedDict ''' 基于LRU,近期最少用缓存算法写的装饰器. ''' class LRUCacheDict: def __init__(self, max_size=

  • Python实现对一个函数应用多个装饰器的方法示例

    本文实例讲述了Python实现对一个函数应用多个装饰器的方法.分享给大家供大家参考,具体如下: 下面的例子展示了对一个函数应用多个装饰器,可以加多个断点,在debug模式下,查看程序的运行轨迹... #!/usr/bin/env python #coding:utf-8 def decorator1(func): def wrapper(): print 'hello python 之前' func() return wrapper def decorator2(func): def wrapp

  • 编写一个javascript元循环求值器的方法

    在上一篇文章中,我们通过AST完成了微信小程序组件的多端编译,在这篇文章中,让我们更深入一点,通过AST完成一个javascript元循环求值器 结构 一个元循环求值器,完整的应该包含以下内容: tokenizer:对代码文本进行词法和语法分析,将代码分割成若干个token parser:根据token,生成AST树 evaluate:根据AST树节点的type,执行对应的apply方法 apply:根据环境,执行实际的求值计算 scope:当前代码执行的环境 代码目录 根据结构看,我将代码目录

  • Python使用PyQt5/PySide2编写一个极简的音乐播放器功能

    疫情肆虐,憋在家实在无聊,索性写点东西,于是就有了这个极极极极极简的音乐播放器. 这个极极极简的音乐播放器类似于"阅后即焚"的软件,播放器可以随机播放歌曲,获取下一首歌曲,不能重新播放上一首歌曲,不能获取歌曲的名称和演唱者.听过的歌曲,就像过眼云烟,放完即散. 下面来看看如何用Python实现这个音乐播放器软件吧! 一.创建UI界面 首先,我们来创建这个播放器的UI界面.这个播放器一共有6个控件: 左上角的程序关闭按钮: 左侧的播放状态标签: 顶部的slogan; 播放/暂停按钮: 下

  • Python实现调用另一个路径下py文件中的函数方法总结

    本文实例讲述了Python实现调用另一个路径下py文件中的函数方法.分享给大家供大家参考,具体如下: 针对这个问题,网上有很多的解决方式.其实最主要的原因是因为Python无法正确找到你其他文件夹下文件的路径.针对不同的环境和问题有不同的方法,大家可自行测试. 1. 方法一 首先,我先把解决我本人问题的方法记录如下.环境,Python为3.5,pycharm工作区间.主文件(main_preprocess.py)需要运用split_by_date.py中的函数,main_preprocess与s

  • Python函数装饰器实现方法详解

    本文实例讲述了Python函数装饰器实现方法.分享给大家供大家参考,具体如下: 编写函数装饰器 这里主要介绍编写函数装饰器的相关内容. 跟踪调用 如下代码定义并应用一个函数装饰器,来统计对装饰的函数的调用次数,并且针对每一次调用打印跟踪信息. class tracer: def __init__(self,func): self.calls = 0 self.func = func def __call__(self,*args): self.calls += 1 print('call %s

  • Python类装饰器实现方法详解

    本文实例讲述了Python类装饰器.分享给大家供大家参考,具体如下: 编写类装饰器 类装饰器类似于函数装饰器的概念,但它应用于类,它们可以用于管理类自身,或者用来拦截实例创建调用以管理实例. 单体类 由于类装饰器可以拦截实例创建调用,所以它们可以用来管理一个类的所有实例,或者扩展这些实例的接口. 下面的类装饰器实现了传统的单体编码模式,即最多只有一个类的一个实例存在. instances = {} # 全局变量,管理实例 def getInstance(aClass, *args): if aC

  • 详解python中的生成器、迭代器、闭包、装饰器

    迭代是访问集合元素的一种方式.迭代器是一个可以记住遍历的位置的对象.迭代器对象从集合的第一个元素开始访问,直到所有的元素被访问完结束.迭代器只能往前不会后退. 1|1可迭代对象 以直接作用于 for 循环的数据类型有以下几种: 一类是集合数据类型,如 list . tuple . dict . set . str 等: 一类是 generator ,包括生成器和带 yield 的generator function. 这些可以直接作用于 for 循环的对象统称为可迭代对象: Iterable .

  • python @propert装饰器使用方法原理解析

    这篇文章主要介绍了python @propert装饰器使用方法原理解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下 首先,@propert的作用是把类中的方法『变成』了属性,方便通过实例访问.propert可以有两种用法:可以把一个方法变成只读属性:可以对一些属性进行过滤. 想象这样一个场景,在实例化一个类之后,需要对类的一个属性进行赋值,这时候是没有对属性属性被赋予的值进行判断的,如果属性被赋予了一个不合适的值,那么代码在后面执行的时候就会

  • Python装饰器实现方法及应用场景详解

    应用场景: 1.授权(Authorization) 装饰器能有助于检查某个人是否被授权去使用一个web应用的端点(endpoint).它们被大量使用于Flask和Django web框架中.这里是一个例子来使用基于装饰器的授权: from functools import wraps # 最新版python引用是 import functools def requires_auth(f): # f 就是我们需要装饰的函数,一看就是不带参数的装饰器 @wraps(f) # 新版python写法 @

随机推荐