Python - 如何为基于类的装饰器指定可选参数?
我想知道怎么写一个这样的装饰器。我希望在调用装饰器的时候,可以指定最大点击次数(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]
2 个回答
4
如果你使用的是3.2版本或更高的版本,别自己写,直接用 from functools import lru_cache
这个就行了。
如果你想支持不带括号的写法,最好使用一个特殊的值作为函数的参数,而不是去检查“错误”的参数。也就是说:
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)
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...]