python - 我如何编写用于缓存的python装饰器?

标签 python caching decorator python-decorators

我正在尝试为 memoize 编写 python 装饰器。 我有几个问题。

  1. @memoize 如何转化为 memoize 类的调用函数?
  2. 为什么 init 需要参数。
  3. 缓存存储在哪里?它与每个函数相关联还是一个全局变量?即如果我使用@memoize 是否会有两个缓存对象 多种功能。

..

class memoize:
    def __init__(self):
        self.cache = {}

    def __call__(self, function):
        def wrapper(*args, **kwargs):
            key = str(function.__name__) + str(args) + str(kwargs)
            if key in cache:
                return cache[key]
            else:
                value = function(*args, **kwargs)
                cache[key] = value
                return value
        return wrapper

@memoize
def fib(n):
    if n in (0, 1):
        return 1
    else:
        return fib(n-1) + fib(n-2)

for i in range(0, 10):
    print(fib(i))

我遇到了编译错误。

Traceback (most recent call last):
  File "memoize.py", line 17, in <module>
    @memoize
TypeError: __init__() takes exactly 1 argument (2 given)

最佳答案

  1. 你应该记住 @decorator 只是 func = decorator(func) 的语法糖。所以这里有一个区别:

(1)

@decorator 
def func():
     ...

相同
func = decorator(func)  # Just call of __init__
func(...)               # Call of decorator.__call__

但是 (2)

@decorator(some_param)
def func():
     ...

类似于

# Call of __init__ plus call of __call__
func = decorator(some_param)(func)  
# Call of closure returned by decorator.__call__
func(...)   
  1. 您已经为 (2) 语法实现了装饰器接受参数,但在使用它们时不要像示例 (1) 那样提供它们。这就是为什么 __init__ 提示,它接收 func 作为第二个参数。

  2. 你应该在wrapper 闭包中编写self.cache,这样wrapper 就会引用相应的装饰器 对象。只写 cache 会导致全局变量搜索,因此会失败。

UPD:我将您的代码更改为方法 (1):

class memoize:
    def __init__(self, function):
        self.cache = {}
        self.function = function

    def __call__(self, *args, **kwargs):        
        key = str(args) + str(kwargs)
        if key in self.cache:
            return self.cache[key]

        value = self.function(*args, **kwargs)
        self.cache[key] = value
        return value

@memoize
def fib(n):
    if n in (0, 1):
        return 1
    else:
        return fib(n-1) + fib(n-2)

for i in range(0, 10):
    print(fib(i))

print(fib.cache)

关于python - 我如何编写用于缓存的python装饰器?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/28145601/

相关文章:

java - java中线程安全的随机访问循环数组?

java - 向任何 java 异常添加属性

python - 向装饰器添加参数会删除 cls 参数

带参数的 Python Matplotlib 回调函数

python - reshape Pandas 数据框将一行反转为多列

node.js - NuxtServerError 状态码为 500,但错误消息为 401 错误

typescript ,装饰异步功能

python - Gtk:如何在带有与整个文件相关的滚动条的 TextView 中获取文件的一部分

python - 使用 re 和 urllib.request 模块

caching - 如何开始使用 Web 缓存、CDN 和代理服务器?