我如何编写 python 缓存装饰器?
How can i write python decorator for caching?
我正在尝试为 memoize 编写 python 装饰器。
我有几个问题。
- @memoize 如何转换为 memoize class 的 call 函数?
- 为什么 init 需要参数。
- 缓存存储在哪里?它与每个函数相关联还是一个全局变量?即如果我使用@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)
- 你应该记住
@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(...)
您已经为 (2) 语法实现了装饰器接受参数,但在使用它们时不要像示例 (1) 那样提供它们。这就是为什么 __init__
抱怨,它接收 func
作为第二个参数。
您应该在 wrapper
闭包中编写 self.cache
,这样 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)
我正在尝试为 memoize 编写 python 装饰器。 我有几个问题。
- @memoize 如何转换为 memoize class 的 call 函数?
- 为什么 init 需要参数。
- 缓存存储在哪里?它与每个函数相关联还是一个全局变量?即如果我使用@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)
- 你应该记住
@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(...)
您已经为 (2) 语法实现了装饰器接受参数,但在使用它们时不要像示例 (1) 那样提供它们。这就是为什么
__init__
抱怨,它接收func
作为第二个参数。您应该在
wrapper
闭包中编写self.cache
,这样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)