我怎么能写python装饰器进行缓存?

use*_*517 5 python caching decorator python-decorators

我正在尝试为memoize编写python decorator.我几乎没有问题.

  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))
Run Code Online (Sandbox Code Playgroud)

我收到了编译错误.

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

mya*_*aut 5

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

(1)

@decorator 
def func():
     ...
Run Code Online (Sandbox Code Playgroud)

和...一样

func = decorator(func)  # Just call of __init__
func(...)               # Call of decorator.__call__
Run Code Online (Sandbox Code Playgroud)

但(2)

@decorator(some_param)
def func():
     ...
Run Code Online (Sandbox Code Playgroud)

类似于

# Call of __init__ plus call of __call__
func = decorator(some_param)(func)  
# Call of closure returned by decorator.__call__
func(...)   
Run Code Online (Sandbox Code Playgroud)
  1. 您已经为(2)语法实现了装饰器接受参数,但在使用它们时不提供它们,如示例(1)所示.这就是为什么__init__抱怨,它接受func作为第二个论点.

  2. 你应该写self.cache一个wrapper闭包,所以wrapper会引用相应的decorator对象.写入只会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)
Run Code Online (Sandbox Code Playgroud)