我如何写这样的装饰器。我希望能够在调用装饰器时指定max_hits的值(或者可选地将其保留)。
,例如,期望的用途是
@memoize(max_hits=7)
def a(val):
print val
或
@memoize
def a(val):
print val
(使用第一个示例给出了有关不正确参数的错误。)
装饰:
class memoize:
"""A decorator to cache previosly seen function inputs.
usage:
@memoize
def some_func(..
"""
def __init__(self, function, max_hits=None):
self.max_hits = max_hits
self.function = function
self.memoized = {}
def __call__(self, *args, **kwargs):
key = (args,tuple(kwargs.items()))
try:
return self.memoized[key]
except KeyError:
self.memoized[key] = self.function(*args,**kwargs)
return self.memoized[key]
答案 0 :(得分:8)
你必须使memoize
一个带有可选参数max_hits
的函数并返回一个装饰器(即另一个可以将该函数作为第一个参数的可调用对象) ;在这种情况下,您可以使用以下两种语法:
@memoize()
def func(x):
[...]
@memoize(max_hits=7)
def func(x):
[...]
所以,可能有以下几点:
def memoize(max_hits=None):
"""Returns a decorator to cache previosly seen function inputs.
usage:
@memoize()
def some_func(..
"""
class decorator:
def __init__(self, function):
self.max_hits = max_hits
self.function = function
self.memoized = {}
def __call__(self, *args, **kwargs):
key = (args,tuple(kwargs.items()))
try:
return self.memoized[key]
except KeyError:
self.memoized[key] = self.function(*args,**kwargs)
return self.memoized[key]
return decorator
请注意,@memoize()
可以使用,但您原来希望的@memoize
语法不会;在后一种情况下,使用@memoize
进行装饰的函数将作为第一个参数(memoize
)传递给max_hits
。如果您想要处理这种情况,可以按如下方式扩展memoize
:
def memoize(max_hits=None):
if callable(max_hits):
# For sake of readability...
func = max_hits
decorator = memoize(max_hits=None)
return decorator(func)
[...original implementation follows here...]
答案 1 :(得分:4)
如果您使用的是3.2+,请不要自行编写,请改用from functools import lru_cache
如果要支持无括号版本,最好使用函数参数的sentinel值,而不是内省“错误”参数。那就是:
class Memoized(object):
# As per the memoize definition in the question
# Leave out the "*, " in 2.x, since keyword-only arguments are only in 3.x
from functools import partial
_sentinel = object()
def memoize(_f=_sentinel, *, max_hits=None):
if _f is _sentinel:
return partial(Memoized, max_hits=max_hits)
return Memoized(_f, max_hits=max_hits)