2012-07-03 75 views
2

我正在嘗試編寫修改其類的狀態的類方法裝飾器。目前我遇到了麻煩。修改綁定方法及其類的Python裝飾器狀態

側面問題:什麼時候裝飾器被調用?它是在類被實例化的時候加載的,還是在類讀取的讀取期間加載的?

我想要做的是這樣的:

class ObjMeta(object): 
    methods = [] 

    # This should be a decorator that magically updates the 'methods' 
    # attribute (or list) of this class that's being read by the proxying 
    # class below. 
    def method_wrapper(method): 
     @functools.wraps(method) 
     def wrapper(*args, **kwargs): 
      ObjMeta.methods.append(method.__name__) 
      return method(*args, **kwargs) 
     return wrapper 

    # Our methods 
    @method_wrapper 
    def method1(self, *args): 
     return args 

    @method_wrapper 
    def method2(self, *args): 
     return args 


class Obj(object): 

    klass = None 

    def __init__(self, object_class=ObjMeta): 
     self.klass = object_class 
     self._set_methods(object_class) 

    # We dynamically load the method proxies that calls to our meta class 
    # that actually contains the methods. It's actually dependent to the 
    # meta class' methods attribute that contains a list of names of its 
    # existing methods. This is where I wanted it to be done automagically with 
    # the help of decorators 
    def _set_methods(self, object_class): 
     for method_name in object_class: 
      setattr(self, method_name, self._proxy_method(method_name)) 

    # Proxies the method that's being called to our meta class 
    def _proxy_method(self, method_name): 
     def wrapper(*fargs, **fkwargs): 
      return getattr(self.klass(*fargs, **fkwargs), method_name) 
     return wrapper() 

我認爲這是醜陋的類手工編寫的方法列表,這樣也許會裝飾解決這個問題。

這是一個開源項目,我正在將端口underscore.js工作到python。我明白,它說我應該只使用itertools什麼的。我只是爲了愛編程和學習而做這個。順便說一句,項目託管here

謝謝!

+0

裝飾者應該在創建類對象時運行。 (*不是*當這個類的實例正在創建時。)這通常發生在第一次導入模塊時。 – millimoose

+0

謝謝!這回答了我的另一個問題。幫助很多。 – jpanganiban

+1

這與函數式編程有什麼關係? – Ben

回答

1

這裏有一些錯誤。

當調用方法本身時,內部包裝中的任何內容都會被調用。基本上,你用這個函數替換原來的方法。所以,你的代碼在它每次調用時會將方法名稱添加到列表中,這可能不是你想要的。相反,該附加應該在method_wrapper級別,即內部包裝之外。這是在定義方法時調用的,這是在第一次導入包含該類的模塊時發生的。

錯誤的第二件事是,你從來沒有實際調用該方法 - 你只需返回它。而不是return method您應該返回使用提供的參數調用方法的值 - return method(*args, **kwargs)

+0

哎呀。你是對的。我應該返回傳入的方法和* args和** kwargs。我將編輯上面的代碼。至於你的回答,你也可能就在那裏。我會放棄並回傳。謝謝。 – jpanganiban

+0

太棒了!得到它的工作。我創建了另一個由ObjMeta繼承的類,它包含'methods'屬性,這就是我在method_wrapper中修改的內容:ObjMetaMeta.methods.append(method .__ name__) – jpanganiban