2017-07-09 203 views
0

這是我想念幾種語言的功能,並想知道是否有人有任何想法如何在Python中完成。從基類__init__的子類__init__調用基類方法?

的想法是,我有一個基類:

class Base(object): 
    def __init__(self): 
     self.my_data = 0 
    def my_rebind_function(self): 
     pass 

和派生類:

class Child(Base): 
    def __init__(self): 
     super().__init__(self) 
     # Do some stuff here 
     self.my_rebind_function() # <==== This is the line I want to get rid of 
    def my_rebind_function(self): 
     # Do stuff with self.my_data 

正如從上面可以看出,我有欲稱爲後反彈功能Child.__init__已經完成了它的工作。我希望對所有繼承的類都完成這個工作,所以如果它是由基類執行的話,那將非常好,所以我不必在每個子類中重新輸入那一行。

如果語言有一個功能類似__finally__,操作類似,它如何與例外操作這將是很好。也就是說,它應該在所有派生類的函數全部運行之後運行,這很好。所以通話順序如下:

Base1.__init__() 
... 
BaseN.__init__() 
LeafChild.__init__() 
LeafChild.__finally__() 
BaseN.__finally__() 
... 
Base1.__finally__() 

然後對象構造完成。這也是一種類似於setuprunteardown功能單元測試。

+0

要覆蓋在少兒班這種方法嗎? – PRMoureu

+0

不,我希望在調用所有孩子的__init __-函數後調用另一個函數。 – Robert

+0

你可以用元類來實現,albiet更復雜:\ – direprobs

回答

1

我可能還沒有完全理解,但是這似乎做什麼,我(覺得)你想:

class Base(object): 
    def __init__(self): 
     print("Base.__init__() called") 
     self.my_data = 0 
     self.other_stuff() 
     self.my_rebind_function() 

    def other_stuff(self): 
     """ empty """ 

    def my_rebind_function(self): 
     """ empty """ 

class Child(Base): 
    def __init__(self): 
     super(Child, self).__init__() 

    def other_stuff(self): 
     print("In Child.other_stuff() doing other stuff I want done in Child class") 

    def my_rebind_function(self): 
     print("In Child.my_rebind_function() doing stuff with self.my_data") 

child = Child() 

輸出:

Base.__init__() called 
In Child.other_stuff() doing other stuff I want done in Child class 
In Child.my_rebind_function() doing stuff with self.my_data 
+0

這解決了這個問題,非常好,但是這個解決方案有一個問題。現在我必須有'other_stuff'方法,它實際上代替了'Child'類中'__init_'方法。所以,現在'Child'類的用戶必須將代碼從其正常位置('__init__')移動到某種新方法('other_stuff')。 – Robert

+0

Child-class的_user_贏得了它的任何代碼。它的實現者只需將所需的代碼放在不同的地方(方法)。對我來說聽起來不是什麼大不了的事...... – martineau

0

如果你想要一個「重新綁定」功能是從Base繼承實例化一個類型的每個實例之後被調用,那麼我會說這個「重新綁定」功能,可以住Base類(或它繼承任何類)之外。

你可以有一個工廠的功能,讓你當你調用它(例如give_me_a_processed_child_object()),你需要的對象。這個工廠函數基本上實例化一個對象,並在它返回給你之前做一些事情。

__init__把邏輯是不是一個好主意,因爲它模糊邏輯和意圖。當你編寫kid = Child()時,你不會指望在後臺發生很多事情,尤其是那些在剛剛創建的Child實例上發生的事情。你期望的是一個新的例子Child

一個工廠的功能,但是,透明地做了一個對象,並返回給你。這樣你就知道你正在得到一個已經處理過的實例。

最後,您希望避免在您的Child類中添加「重新綁定」方法,因爲所有的邏輯都可以放在工廠函數中。

0

爲此,您可以用這樣的一個元類:

class Meta(type): 
     def __call__(cls, *args, **kwargs): 
      print("start Meta.__call__") 
      instance = super().__call__(*args, **kwargs) 
      instance.my_rebind_function() 
      print("end Meta.__call__\n") 
      return instance 


    class Base(metaclass=Meta): 
     def __init__(self): 
      print("Base.__init__()") 
      self.my_data = 0 

     def my_rebind_function(self): 
      pass 


    class Child(Base): 
     def __init__(self): 
      super().__init__() 
      print("Child.__init__()") 

     def my_rebind_function(self): 
      print("Child.my_rebind_function") 
      # Do stuff with self.my_data 
      self.my_data = 999 


    if __name__ == '__main__': 
     c = Child() 
     print(c.my_data) 

通過覆蓋元類.__ call__你都可以__init__(和__new__)類樹的方法之後的掛鉤已經返回實例之前運行。這是調用你的rebind函數的地方。爲了理解呼叫次序,我添加了一些打印語句。輸出將是這樣的:

start Meta.__call__ 
Base.__init__() 
Child.__init__() 
Child.my_rebind_function 
end Meta.__call__ 

999 

如果你想閱讀,並得到更深入的細節,我可以推薦以下大文章:https://blog.ionelmc.ro/2015/02/09/understanding-python-metaclasses/