简体   繁体   English

Python:装饰器特定参数(与包装函数无关)?

[英]Python: decorator specific argument (unrelated to wrapped function)?

I'm looking to build a caching decorator that given a function caches the result of the function to a location specified in the decoration.我正在寻找一个缓存装饰器,给定 function 将 function 的结果缓存到装饰中指定的位置。 Something like this:像这样的东西:

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

The argument to the decorator is completely separate from the argument to the function it's wrapping.装饰器的参数与它包装的 function 的参数完全分开。 I've looked at quite a few examples but I'm not quite getting how to do this - is it possible to have an argument for the decorator that's unrelated to and not passed to the wrapped function?我已经看过很多例子,但我不太明白如何做到这一点 - 是否有可能为装饰器提供一个与包装的 function 无关且未传递的参数?

The idea is that your decorator is a function returning a decorator.这个想法是你的装饰器是一个 function 返回一个装饰器。

FIRST Write your decorator as if you knew your argument was a global variable.首先编写你的装饰器,就好像你知道你的参数是一个全局变量一样。 Let's say something like:让我们这样说:

- -

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 Write a function that takes cachepath as an arg and return your decorator.然后编写一个function ,它将缓存路径作为参数并返回您的装饰器。

- -

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

Yes it is.是的。 As you know, a decorator is a function.如您所知,装饰器是 function。 When written in the form:当写成表格时:

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

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

the argument passed to mydecorator is the function foo itself.传递给mydecorator的参数是 function foo本身。

When the decorator accepts an argument, the call @mydecorator('/path/to') is actually going to call the mydecorator function with '/path/to' first.当装饰器接受一个参数时,调用@mydecorator('/path/to')实际上将首先调用带有'/path/to' 的mydecorator function。 Then the result of the call to mydecorator(path) will be called to receive the function foo .然后调用mydecorator(path)的结果来接收 function foo You're effectively defining a dynamic wrapper function.您实际上是在定义一个动态包装器 function。

In a nutshell, you need another layer of decorator functions.简而言之,您需要另一层装饰器功能。

Here is this slightly silly example:这是这个有点愚蠢的例子:

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

Paul's answer is good, I would move the cache object so it doesn't need to be built every time, and design your cache so that it raises KeyError when there is a cache miss:保罗的回答很好,我会移动缓存 object 所以它不需要每次都构建,并设计你的缓存,以便在缓存未命中时引发 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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM