Python 类装饰器参数

新手上路,请多包涵

我正在尝试将可选参数传递给我的 python 类装饰器。在我目前拥有的代码下方:

 class Cache(object):
    def __init__(self, function, max_hits=10, timeout=5):
        self.function = function
        self.max_hits = max_hits
        self.timeout = timeout
        self.cache = {}

    def __call__(self, *args):
        # Here the code returning the correct thing.

@Cache
def double(x):
    return x * 2

@Cache(max_hits=100, timeout=50)
def double(x):
    return x * 2

第二个带有覆盖默认装饰器参数的装饰器( max_hits=10, timeout=5 在我的 __init__ 函数中)不起作用,我得到了异常 TypeError: __init__() takes at least 2 arguments (3 given) .我尝试了很多解决方案并阅读了有关它的文章,但在这里我仍然无法使其工作。

有解决这个问题的想法吗?谢谢!

原文由 Dachmt 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 571
2 个回答

@Cache(max_hits=100, timeout=50) 调用 __init__(max_hits=100, timeout=50) ,所以你不满足 function 论点。

您可以通过检测函数是否存在的包装方法来实现您的装饰器。如果它找到一个函数,它可以返回 Cache 对象。否则,它可以返回一个将用作装饰器的包装函数。

 class _Cache(object):
    def __init__(self, function, max_hits=10, timeout=5):
        self.function = function
        self.max_hits = max_hits
        self.timeout = timeout
        self.cache = {}

    def __call__(self, *args):
        # Here the code returning the correct thing.

# wrap _Cache to allow for deferred calling
def Cache(function=None, max_hits=10, timeout=5):
    if function:
        return _Cache(function)
    else:
        def wrapper(function):
            return _Cache(function, max_hits, timeout)

        return wrapper

@Cache
def double(x):
    return x * 2

@Cache(max_hits=100, timeout=50)
def double(x):
    return x * 2

原文由 lunixbochs 发布,翻译遵循 CC BY-SA 3.0 许可协议

@Cache
def double(...):
   ...

相当于

def double(...):
   ...
double=Cache(double)

尽管

@Cache(max_hits=100, timeout=50)
def double(...):
   ...

相当于

def double(...):
    ...
double = Cache(max_hits=100, timeout=50)(double)

Cache(max_hits=100, timeout=50)(double) Cache(double) 非常不同的语义。

尝试让 Cache 处理这两种用例是不明智的。

您可以改用装饰器工厂,它可以采用可选的 max_hitstimeout 参数,并返回一个装饰器:

 class Cache(object):
    def __init__(self, function, max_hits=10, timeout=5):
        self.function = function
        self.max_hits = max_hits
        self.timeout = timeout
        self.cache = {}

    def __call__(self, *args):
        # Here the code returning the correct thing.

def cache_hits(max_hits=10, timeout=5):
    def _cache(function):
        return Cache(function,max_hits,timeout)
    return _cache

@cache_hits()
def double(x):
    return x * 2

@cache_hits(max_hits=100, timeout=50)
def double(x):
    return x * 2

附言。 If the class Cache has no other methods besides __init__ and __call__ , you can probably move all the code inside the _cache function and eliminate Cache 一共。

原文由 unutbu 发布,翻译遵循 CC BY-SA 3.0 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题