2016-11-10 137 views
4

我有一些python對象,其中有些方法需要在開始時進行一些檢查,具體取決於此檢查,方法的代碼將運行或執行會被提出。我不是在每個方法的開頭都複製「check」代碼,而是在做一個裝飾器,但我也希望裝飾器被嵌入到類本身內部,因爲它與它密切相關。所以基本上:在基類和派生類中使用基類的裝飾器

,而不是這個

class A(object): 

    def a_method(self): 
     if self.check_var is True: 
      (some_code) 
     else: 
      raise Exception 

我想有這個

class A(object): 

    def decorator(function): 
     def function_wrapper(self, *args, **kwargs): 
      if self.check_var is True: 
       return function(self, *args, **kwargs) 
      else: 
       raise Exception 
     return function_wrapper 

    @decorator 
    def a_method(self): 
     (some_code) 

我的第一個問題是,我要對這個權利?或者,還有更好的方法。我有許多需要進行此檢查的A類方法,所以這就是爲什麼我不想不必要地複製代碼的原因。

我的第二個問題是,如果按照我描述的方式進行操作,當我想從A類派生類並執行相同的裝飾器檢查時遇到問題。再次我不想複製代碼,所以我想重用基類A中的裝飾器來執行派生類中的檢查。我讀過關於將裝飾器轉換爲@classmethod然而,當我這樣做時,我可以在派生類中使用裝飾器,但不能在基類中使用裝飾器!

所以基本上我想是這樣的:

class A(object): 

    @classmethod #maybe 
    def decorator(function): 
     def function_wrapper(self, *args, **kwargs): 
      if self.check_var is True: 
       return function(self, *args, **kwargs) 
      else: 
       raise Exception 
     return function_wrapper 

    @decorator 
    def a_method(self): 
     (some_code) 

class B(A): 

    @decorator 
    def b_method(self): 
     (some_code) 

有誰知道任何干淨的方式做到這一點?

+4

只需在兩個類之外和之前定義'decorator()'。 – martineau

+0

我想在課堂內有裝飾器...裝飾做的東西是對類 – viterbi

+1

把你的基類的文件(模塊)與裝飾非常相關的,這種方式是很明顯的,他們屬於一個整體,然後就做什麼@martineau說 – user3012759

回答

3

既然你寧願把裝飾類內(而不是外他們都爲我的意見建議),下面顯示了一個辦法做到這一點。它使裝飾者staticmethod而不是classmethod,並要求以稍微不尋常的方式使用它,但只有類。

有關使用這樣的裝飾的需要的更多信息,請參閱我的問題,以避免使用__func__,仍然保持定義第一類Calling class staticmethod within the class body?

class A(object): 
    @staticmethod 
    def decorator(function): 
     def function_wrapper(*args, **kwargs): 
      print('in function_wrapper') 
      return function(*args, **kwargs) 
     return function_wrapper 

    @decorator.__func__ #### Note unusual decorator usage inside defining class 
    def a_method(self): 
     print('in a_method') 

class B(A): 
    @A.decorator #### Normal decorator usage outside defining class 
    def b_method(self): 
     print('in b_method') 

一種方法是推遲轉彎它變成staticmethod直到類定義的末尾:

class A(object): 
    def decorator(function): 
     def function_wrapper(*args, **kwargs): 
      print('in function_wrapper') 
      return function(*args, **kwargs) 
     return function_wrapper 

    @decorator 
    def a_method(self): 
     print('in a_method') 

    decorator = staticmethod(decorator) #### convert for use outside this class 

class B(A): 
    @A.decorator 
    def b_method(self): 
     print('in b_method') 

另一種方法,以避免__func__是這樣的:

class A(object): 
    class Check: 
     @staticmethod 
     def decorator(function): 
      def function_wrapper(*args, **kwargs): 
       print('in function_wrapper') 
       return function(*args, **kwargs) 
      return function_wrapper 

    @Check.decorator 
    def a_method(self): 
     print('in a_method') 

class B(A): 
    Check = A.Check 

    @Check.decorator 
    def b_method(self): 
     print('in b_method') 

它具有使裝飾者的使用非常均勻的優點。

+0

謝謝@馬蒂奧!似乎工作 – viterbi

0

My first question is, am I going about this right?

正如馬蒂諾在下面說的,好的做法是把經典的裝飾者放在課外。

def get_decorator(function, argument): 
    def function_wrapper(*args, **kwargs): 
     if argument is True: 
      return function(*args, **kwargs) 
     else: 
      raise Exception 
    return function_wrapper 

class A(object): 
    def __init__(self): 
     self.check_var = True 
     self.a_method = get_decorator(self.a_method, self.check_var) 
    def a_method(self): 
     (whatever) 

class B(A): 
    def __init__(self): 
     super(B, self).__init__() 
     self.b_method = get_decorator(self.b_method, self.check_var) 
    def b_method(self): 
     (whatever) 

Classic decorator is called during class creation time, which is long before an instance is created. Reference

+0

我想你錯過了OP希望在類「A」和子類「B」中使用裝飾器的觀點。在定義它的類中調用/使用classmethod裝飾器將導致'TypeError:'classmethod'對象不可調用'。 – martineau

+0

是的我知道,我只是想多重繼承,但它似乎不是一個好的解決方案。 –

+0

所以你的答案的第二部分不會解決OP的需求。 – martineau