Python:decorator特定的参数(与包装函数无关)?

时间:2009-03-19 01:11:03

标签: python decorator

我正在寻找一个缓存装饰器,它给出一个函数将函数的结果缓存到装饰中指定的位置。像这样:

@cacheable('/path/to/cache/file')
def my_function(a, b, c):
    return 'something'

装饰器的参数与它包装的函数的参数完全分开。我已经看了很多例子,但是我还没有完成如何做到这一点 - 是否有可能为装饰器提供一个与包装函数无关且不传递给包装函数的参数?

3 个答案:

答案 0 :(得分:9)

这个想法是你的装饰器是一个返回装饰器的函数。

第一次写你的装饰者,好像你知道你的论证是一个全局变量。我们这样说:

-

def decorator(f):
  def decorated(*args,**kwargs):
      cache = Cache(cachepath)
      if cache.iscached(*args,**kwargs):
          ...
      else:
          res = f(*args,**kwargs)
          cache.store((*args,**kwargs), res)
          return res
  return decorated

THEN 编写一个将cachepath作为arg并返回装饰器的函数。

-

def cache(filepath)
    def decorator(f):
      def decorated(*args,**kwargs):
          cache = Cache(cachepath)
          if cache.iscached(*args,**kwargs):
              ...
          else:
              res = f(*args,**kwargs)
              cache.store((*args,**kwargs), res)
              return res
      return decorated
    return decorator

答案 1 :(得分:5)

是的。如您所知,装饰器是一种功能。写在表格中时:

def mydecorator(func):
   def wrapper(*args, **kwargs):
       return func(*args, **kwargs)
   return wrapper

@mydecorator
def foo(a, b, c):
    pass

传递给mydecorator的参数是函数foo本身。

当装饰器接受参数时,调用@mydecorator('/path/to')实际上将首先使用'/ path / to'调用mydecorator函数。然后将调用mydecorator(path)调用的结果来接收函数foo。您正在有效地定义动态包装函数。

简而言之,您需要另一层装饰器功能。

这是一个有点愚蠢的例子:

def addint(val):
    def decorator(func):
        def wrapped(*args, **kwargs):
            result = func(*args, **kwargs)
            return result + val
        return wrapped # returns the decorated function "add_together"
     return decorator # returns the definition of the decorator "addint"
                      # specifically built to return an extra 5 to the sum

@addint(5)
def add_together(a, b):
    return a + b

print add_together(1, 2)
# prints 8, not 3

答案 2 :(得分:3)

Paul的答案很好,我会移动缓存对象,因此不需要每次都构建它,并设计缓存,以便在缓存未命中时引发KeyError:

def cache(filepath):
    def decorator(f):
        f._cache = Cache(cachepath)
        def decorated(*args,**kwargs):
            try:
                key = (args, kwargs)
                res = f._cache.get(key)
            except KeyError:
                res = f(*args, **kwargs)
                f._cache.put(key, res)
            return res
        return decorated
    return decorator