2010-09-13 46 views
4

你可以創建一個類,將看到類方法和變量內部裝飾?創建裝飾,可以看到當前類方法

的裝飾在這裏看到犯規:self.longcondition()

class Foo: 
    def __init__(self, name): 
     self.name = name 

    # decorator that will see the self.longcondition ??? 
    class canRun(object): 
      def __init__(self, f): 
       self.f = f 

      def __call__(self, *args): 
       if self.longcondition(): # <-------- ??? 
        self.f(*args) 

    # this is supposed to be a very long condition :) 
    def longcondition(self): 
     return isinstance(self.name, str) 

    @canRun # <------ 
    def run(self, times): 
     for i in xrange(times): 
      print "%s. run... %s" % (i, self.name) 

回答

1

你可以擁有它是一類,但你需要使用描述協議

import types 

class canRun(object): 
    def __init__(self, f): 
     self.f = f 
     self.o = object # <-- What the hell is this about? 

    def __call__(self, *args): 
     if self.longcondition(): 
      self.f(*args) 

    def __get__(self, instance, owner): 
     return types.MethodType(self, instance) 

你總是當你想用類實例使用__call__方法來修飾類方法時,需要使用描述符。原因是隻有一個self傳入,其中引用了裝飾類的實例而不是裝飾方法的實例。

1

我以前的答案是草率作出。如果你想寫一個裝飾器,你應該使用functools模塊中的wraps。它爲您處理困難的事情。

一個適當的方式來定義所述裝飾canRun是:

from functools import wraps 
def canRun(f): 
    @wraps(f) 
    def wrapper(instance, *args): 
    if instance.longcondition(): 
     return f(instance, *args) 
    return wrapper 

的canRun函數應的類的外部限定。

+0

這不工作,也沒有理由認爲它應該。你想要一個描述符。看到我的答案。 – aaronasterling 2010-09-13 21:42:03

+0

@aaronasterling,你是對的。我基於以前使用functools.wraps的經驗回答了這個問題,但沒有經過測試,看看它是否有效。我已更新我的答案以使用它 – 2010-09-13 22:38:41

5

有實現這個裝飾爲一類沒有真正的需要,而且也沒有必要實現它的Foo類的定義裏面。以下就足夠了:

def canRun(meth): 
    def decorated_meth(self, *args, **kwargs): 
     if self.longcondition(): 
      print 'Can run' 
      return meth(self, *args, **kwargs) 
     else: 
      print 'Cannot run' 
      return None 
    return decorated_meth 

使用裝飾似乎工作:

>>> Foo('hello').run(5) 
Can run 
0. run... hello 
1. run... hello 
2. run... hello 
3. run... hello 
4. run... hello 
>>> Foo(123).run(5) 
Cannot run 
+0

請注意,此實現假定它將裝飾綁定方法,因此不能用於裝飾任意函數。 – 2010-09-13 21:11:02