2011-09-19 56 views
4

注意使用父類的裝飾:Python的裝飾:如何在子類

對其他問題接受的答案顯示瞭如何使用父decorater。

該問題的接受答案顯示將裝飾器移動到模塊範圍。


編輯:使用前面的例子是一個壞主意。希望這是更清晰:

class A: 
    def deco(func): 
     print repr(func) 
     def wrapper(self, *args): 
      val = func(*args) 
      self.do_something() 
      return val 
     return wrapper 

    def do_something(self): 
     # Do something 
     print 'A: Doing something generic for decoration' 

    @deco 
    def do_some_A_thing (self): 
     # Do something 
     print 'A: Doing something generic' 

class B (A): 

    @deco 
    def do_some_B_thing(self): 
     # Do something 
     print "B: Doing something specific" 

a = A() 
b = B() 
a.do_some_A_thing() 
b.do_some_B_thing() 

#Expected Output: 
    #A: Doing something generic 
    #A: Doing something generic for decoration 
    #B: Doing something specific 
    #A: Doing something generic for decoration 

此代碼生成一個NameError:名字「裝飾」不是內部B. 定義的裝飾需要是一流的範圍內,因爲我需要訪問存儲的狀態。

三編輯:在斯文的建議,我嘗試這樣做:

class A: 
    def deco(func): 
     def wrapper(self, *args): 
      val = func(*args) 
      self.do_something(*args) 
      return val 
     return wrapper 

    def do_something(self): 
     # Do something 
     print 'A: Doing something generic for decoration' 

    @deco 
    def do_some_A_thing (self): 
     # Do something 
     print 'A: Doing something generic' 

    deco = staticmethod(deco) 

class B (A): 

    @A.deco 
    def do_some_B_thing(self): 
     # Do something 
     print "B: Doing something specific" 



a = A() 
b = B() 
a.do_some_A_thing() 
b.do_some_B_thing() 

#Expected Output: 
    #A: Doing something generic 
    #A: Doing something generic for decoration 
    #B: Doing something specific 
    #A: Doing something generic for decoration 

我現在有類型錯誤:do_some_A_thing()恰恰(給出0)1個說法。任何指針?

+0

你試過嗎?你有錯誤嗎? – bitcycle

回答

5

問題是繼承對實例屬性查找起作用,而不是類定義。所以當你嘗試用B中的A.deco裝飾時,它找不到它。解決方法是將deco移出模塊範圍,並且由於名稱self沒有什麼魔力,您可以繼續使用它。你還需要明確地傳遞給selffunc,和你做需要通過它self.do_something()。這裏的更新代碼:

def deco(func): 
    print repr(func) 
    def wrapper(self, *args): 
     val = func(self, *args) 
     self.do_something() 
     return val 
    return wrapper 

class A: 
    def do_something(self): 
     # Do something 
     print 'A: Doing something generic for decoration' 

    @deco 
    def do_some_A_thing (self): 
     # Do something 
     print 'A: Doing something generic' 

class B (A): 

    @deco 
    def do_some_B_thing(self): 
     # Do something 
     print "B: Doing something specific" 

a = A() 
b = B() 
a.do_some_A_thing() 
b.do_some_B_thing() 
+0

該解決方案纔會出現,如果子類被同一模塊作爲子類中定義的工作。如果我在其他地方進口的父類和嘗試定義的子類,使用上的子類的方法中的一種裝飾,它不再定義。 – user5359531

+0

@ user5359531:什麼是不再定義? –

+0

我的意思是,如果你從另一個模塊導入 – user5359531

2

回答編輯問題:您的問題已成爲question it linked to before the edit的確切副本。比鏈接問題的答案中給出的更簡單的解決方法是簡單地將裝飾器移出類命名空間。

此外,self.do_something(self)應改爲self.do_something() - 不要通過self兩次。

答到編輯之前的問題:如果您只想裝飾實例方法與你的裝飾,不要self參數坍縮成*args,而是把它明確:

def _deco(func): 
    def wrapper(self, *args): 
     res = func(self, *args) 
     self.some_other_baseclass_method(*args) 
     return res 
    return wrapper 

那說,我沒有看到在類名稱空間中有_deco並將其變爲staticmethod。只需將其移動到模塊名稱空間即可。

+0

謝謝Sven。我的問題措辭很差。我已更新它以更好地反映問題。 – GeneralBecos

+0

@GeneralBecos:更新了我的答案。 –

+0

我嘗試這種方法,它導致類型錯誤:do_some_A_thing()採用完全1參數(0給出)。 – GeneralBecos