Python:使用装饰器模拟实现FIFO缓存

2023-05-16

使用装饰器模拟实现FIFO缓存

在学习python过程中找到一个非常不错的网站,看到博主讲解装饰器的时候给出了模拟FIFO缓存的代码,但是代码中有一些缺陷,本文在学习该博主的代码的基础上,修补了代码中的缺陷。

博主原代码

from functools import wraps
from inspect import signature

def fifo_cache(maxsize=128):
    lst = []
    cache = {}
    def wrapper(func):
        sig = signature(func)
        @wraps(func)
        def inner(*args,**kwargs):
            bond_values = sig.bind(*args,**kwargs)
            key = bond_values.__str__()
            value = cache.get(key)

            if value is not None:
                res = "hit the cache:" + str(value)
                return res
                
            if len(lst) >= maxsize:
                oldkey = lst.pop(0)
                if oldkey in cache:
                    cache.pop(oldkey)
            
            result = func(*args,**kwargs)
            lst.append(key)
            cache[key] = result
            return result
        return inner
    return wrapper

@fifo_cache()
def test1(x, y):
    return x + y


@fifo_cache()
def test2(x, y, z=20):
    return x + y + z


print(test1(19, 20))
print(test1(19, 20))
print(test1(20, 19))

print(test2(19, 20, 20))
print(test2(19, 20))

运行结果:

[root@code-server-lzj vscode-lzj]# /usr/bin/python3 /root/vscode-lzj/python/decorator_demo_2.py
39
hit the cache:39
39
59
59

缺陷:
1、函数test2的最后一个参数z是默认参数,默认值是20, test2(19, 20, 20) 与 test2(19, 20) 本质上传入的参数是相同的,但在inner函数里接收到的参数里没有默认参数的数值,无法命中缓存。
2、当参数值互换位置时,实际上是同一情况,如test1(19,20) test1(20,19)无法命中缓存。

改进之后的代码:

from functools import wraps
from inspect import signature

def fifo_cache(maxsize=128):
    lst = []
    cache = {}
    def wrapper(func):
        sig = signature(func)
        @wraps(func)
        def inner(*args):
            bound_args = sig.bind(*args)
            bound_args.apply_defaults()  # 这个可以获取到函数的默认参数,并且能获取默认参数被覆盖后的值
            target_args = dict(bound_args.arguments)
            key = []
            for v in target_args.values():
                key.append(v)
            key.sort() # 同一对传进来的参数进行排序,就可以判断乱序的同元素
            key = str(key) # 转成字符串再存进字典
            value = cache.get(key)

            if value is not None:
                res = "hit the cache:" + str(value)
                return res
            if len(lst) >= maxsize:
                oldkey = lst.pop(0)
                if oldkey in cache:
                    cache.pop(oldkey)
            
            result = func(*args)
            lst.append(key)
            cache[key] = result
            return result
        return inner
    return wrapper

@fifo_cache()
def test1(x, y):
    return x + y


@fifo_cache()
def test2(x, y, z=20):
    return x + y + z




print(test1(19, 20))
print(test1(20, 19))
print(test1(1,1))


print(test2(19, 20, 20))
print(test2(19, 20))
print(test2(20, 19))
print(test2(20,20,19))
print(test2(20,2,19))

运行结果:

[root@code-server-lzj vscode-lzj]# /usr/bin/python3 /root/vscode-lzj/python/decorator_demo_2.py
39
hit the cache:39
2
59
hit the cache:59
hit the cache:59
hit the cache:59
41

改进后的代码成功地解决了上述的两个缺陷。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Python:使用装饰器模拟实现FIFO缓存 的相关文章

随机推荐