我已经实现了一个memoize
装饰器,它允许缓存一个函数。缓存键包括函数参数。类似地,cached
装饰器缓存一个函数,但忽略了参数。这是代码:
class ApplicationCache (Memcached):
make_key
方法: UltraJSON 快速传递一个字符串,其中 SHA512 哈希成为一个清晰的十六进制摘要:
def make_key (self, *args, **kwargs):
kwargs.update (dict (enumerate (args)))
string = ujson.encode (sorted (kwargs.items ()))
hashed = hashlib.sha512 (string)
return hashed.hexdigest ()
memoize
装饰器:因为Python 2.x糟透了w.r.t.完全限定的函数名称,我只是强迫用户提供合理的name
:
def memoize (self, name, timeout=None):
assert name
def decorator (fn):
@functools.wraps (fn)
def decorated (*args, **kwargs):
key = self.make_key (name, *args, **kwargs)
cached = self.get (key)
if cached is None:
cached = fn (*args, **kwargs)
self.set (key, cached, timeout=timeout)
return cached
return decorated
return decorator
cached
装饰器:它几乎是memoize
的逐字副本,只有make_key
忽略参数的唯一例外:
def cached (self, name, timeout=None):
assert name
def decorator (fn):
@functools.wraps (fn)
def decorated (*args, **kwargs):
key = self.make_key (name) ## no args!
cached = self.get (key)
if cached is None:
cached = fn (*args, **kwargs)
self.set (key, cached, timeout=timeout)
return cached
return decorated
return decorator
现在,我对cached
的问题是,它为重新分解而尖叫:它应该使用memoize
,其目的是消除fn
的参数(使用{{ 1}}也许?),如:
functools.partial
我实际上不确定我是否在这里过度使用DRY原则,如果重用是可能的,因为 def cached (self, name, timeout=None):
## Reuse the more general `memoize` to cache a function,
## but only based on its name (ignoring the arguments)
的当前实现忽略了仅的参数键(但在调用修饰函数时显然不)。
答案 0 :(得分:1)
我将摆脱name
参数并提供关键函数作为参数:
def memoize(self, timeout=None, keyfunc=self.make_key):
...
key = keyfunc(function.__name__, *args, **kwargs)
...
cache
将成为:
def cache(self, timeout=None):
return self.memoize(timeout, keyfunc=lambda f, *args, **kwargs: f.__name__)