2009-03-19 10 views
6

私はキャッシングデコレータをビルドしようとしていますが、関数を指定するとデコレータで指定された場所に関数の結果がキャッシュされます。Python:デコレータ固有の引数(ラップされた関数とは無関係)?

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

デコレータの引数は、ラップする関数の引数とはまったく別です。私はいくつかの例を見てきましたが、これをどうやって行うのか分かりません。ラップされた関数とは無関係で、渡されないデコレータの引数を取ることは可能でしょうか?

答えて

9

あなたのデコレータはデコレータを返す関数です。

FIRST引数がグローバル変数であることがわかっていたかのようにデコレータを作成してください。 THEN引数としてcachepathを取り、あなたのデコレータを返す関数を作成

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 

-

:のようなものを言ってみましょう。

-

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 
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)への呼び出しの結果が呼び出されます。動的ラッパー関数を効果的に定義しています。

一言で言えば、デコレータ機能の別のレイヤーが必要です。ここで

はこの少し愚かな例です:ポールの答えは良いです

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 
3

それはすべての時間を構築する必要はありませんので、私は、キャッシュオブジェクトを移動すると、それは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 
関連する問題