2016-02-09 116 views
1

我在寫一個泛型類裝飾器,它需要將裝飾器應用於每種方法。我的第一種方法是這樣的:如何裝飾類或靜態方法

def class_decorator(cls): 
    for name, member in vars(cls).items(): 
     # Ignore anything that is not a method 
     if not isinstance(member, (types.FunctionType, types.BuiltinFunctionType, classmethod, staticmethod)): 
      continue 

     setattr(cls, name, method_decorator(member)) 

    return cls 

裝飾者本身並不是很重要。看起來是這樣的:

def method_decorator(fn): 
    @functools.wraps(fn) 
    def wrapper(*args, **kwargs): 
     # do something 
     return fn(*args, **kwargs): 

    return wrapper 

一旦我測試了它,我遇到了這個問題,這不具有靜態或類的方法工作,下面的錯誤是從functools.wraps提出:

AttributeError: 'classmethod' object has no attribute '__module__' 

呀,classmethodstaticmethods不是正常的功能,甚至沒有可調用的功能。通常如果你需要裝飾一個classmethod,你首先應用你的裝飾器,然後裝飾器,但由於這是一個類裝飾器,我不能影響裝飾器的順序。

這是什麼好的解決方案?

+0

因爲裝飾引起混淆:綁定對象的類方法不是功能對象(即裝飾返回),因此它不能結合的方法,以班上 –

回答

3

在玩了一段時間之後,我發現了一個解決方案,比我在其他方法中更好看。也許這對別人有幫助。

基本上思想如下:

  • 檢測構件,其是類或靜態方法
  • 獲取這些方法
  • 內包裹函數對象應用裝飾爲此功能
  • 包住裝飾功能classmethodstaticmethod實例
  • 將其存儲在班級中

的代碼看起來是這樣的:

def class_decorator(cls): 
    for name, member in vars(cls).items(): 
     # Good old function object, just decorate it 
     if isinstance(member, (types.FunctionType, types.BuiltinFunctionType)): 
      setattr(cls, name, method_decorator(member)) 
      continue 

     # Static and class methods: do the dark magic 
     if isinstance(member, (classmethod, staticmethod)): 
      inner_func = member.__func__ 
      method_type = type(member) 
      decorated = method_type(method_decorator(inner_func)) 
      setattr(cls, name, decorated) 
      continue 

     # We don't care about anything else 

    return cls