2011-05-19 43 views
5

我正在研究一個Django應用程序,但是這看起來好像只是一個python問題,並不一定專用於Django。我很新的蟒蛇,它很難描述我所試圖做的,但更容易使這裏展示有云:如何一般性地將一個函數的覆蓋應用於python中的多個類?

我有一個類:

class SlideForm(ModelForm): 

    class Meta: 
     model = Slide 

我子類:

class HiddenSlideForm(SlideForm): 
    def __init__(self, *args, **kwargs): 
     super(HiddenSlideForm, self).__init__(*args, **kwargs) 
     for name, field in self.fields.iteritems(): 
      field.widget = field.hidden_widget() 
      field.required = False 

,然後我有另一個類:

class DeckForm(ModelForm):  

    def __init__(self, *args, **kwargs): 
     # do some stuff here 
     return super(DeckForm, self).__init__(*args, **kwargs) 

    class Meta: 
     model = Deck 
     # other stuff here 

,我也分等級:

class HiddenDeckForm(DeckForm): 

    def __init__(self, *args, **kwargs): 
     super(HiddenDeckForm, self).__init__(*args, **kwargs) 
     for name, field in self.fields.iteritems(): 
      field.widget = field.hidden_widget() 
      field.required = False 

請注意,子類具有與類名完全相同的代碼,並執行完全相同的操作。我一直在試圖弄清楚什麼是最好的方式來通用這個,所以我可以保持它乾燥,並很容易地用於其他類,並已考慮裝飾器和/或多重繼承 - 這兩個都是我的新概念 - 但我繼續混淆。

幫助表示讚賞!

(作爲一個方面說明,隨意指出我的Django的代碼:)你看任何問題)

+0

問題應該可能要求解決問題的方法,因此它不涉及在表單中嵌入大量隱藏字段? – 2011-05-19 01:55:18

+0

謝謝你的建議,約翰。發佈了一個單獨的問題,描述了我正在使用的場景。 http://stackoverflow.com/questions/6054124。如果您有一些想法,請隨時發佈答案。我很想弄清楚如何以更清潔的方式實現這一點。 – 2011-05-19 05:23:09

+0

+1用於查找我答案中的錯誤;現在我更瞭解python了! – SingleNegationElimination 2011-05-20 00:59:49

回答

4

一個選項是使用Mixin類;例如:

首先,共同的行爲去的混入:

class SomeMixin(object): 
    def __init__(self, *args, **kwargs): 
     super(SomeMixin, self).__init__(*args, **kwargs) 
     for name, field in self.fields.iteritems(): 
      field.widget = field.hidden_widget() 
      field.required = False 

要你在所有的繼承圖類的合理控制範圍內,因此只要您撥打super在每一種需要重寫的方法,那麼派生類看起來像什麼都沒有關係。

但是,如果其中一個超類在正確的時間沒有自己調用super,則會遇到問題。在這種情況下,重寫的方法必須被稱爲,最後的非常重要,因爲一旦被調用,就不會再有呼叫。

最簡單的解決方案是確保每個類實際上來自違規的超類,但在某些情況下,這是不可能的;派生一個新類創建一個新的對象,你實際上並不想存在!另一個原因可能是因爲邏輯基類遠遠超出了繼承樹的範圍。\

在這種情況下,您需要特別注意列出基本類別的訂單。 Python將首先考慮最左邊的超類,除非在繼承圖中存在更多的派生類。這是一個涉及到的主題,爲了理解python真正的優勢,你應該閱讀Python 2.3和更高版本中的C3 MRO algorithm

基類和以前一樣,但由於大家的代碼來自混入,派生類就變得瑣碎

class HiddenSlideForm(SomeMixin, SlideForm): 
    pass 

class HiddenDeckForm(SomeMixin, DeckForm): 
    pass 

注意,混合類出現第一,因爲我們無法控制*Form類在其init方法中執行。

如果__init__的方法都不平凡,您仍然會獲得勝利。

class HiddenSlideForm(SomeMixin, SlideForm): 
    def __init__(self, *args, **kwargs): 
     super(HiddenSlideForm, self).__init__(*args, **kwargs) 
     do_something_special() 

確保object是在繼承圖,某處。奇怪的事情可能會發生,否則。

+2

感謝您的回覆!我從Django提供的基類繼承(ModelForm),但是你的代碼對我不起作用。 Mixin中的init函數永遠不會被調用。以下是一個簡單的測試案例,演示發生了什麼:http://pastebin.com/a1tnXsjA。任何想法是什麼修復? (順便說一句,我在Python 2.6) – 2011-05-19 07:17:22

+0

而不是使用超級,只需在'HiddenSlideForm .__ init __()'中明確(一個接一個地)調用'SomeMixin'和'SlideForm'的'__init __()'。 – Imran 2011-05-20 07:11:54

+0

Imram,儘管這並不理想,因爲我將不得不在每個子類中編寫一個init,但它看起來可能是實現它的方法,因爲其他建議的用於使用Mixin自動執行覆蓋的想法不會似乎工作。如果您創建了評論的答案形式版本,我會將其標記爲已接受,因爲它實際上可行。 – 2011-05-23 14:28:18

0

多重繼承(具體Mixins)很可能是這裏的最佳解決方案。

例子:

class HiddenFormMixin(object): 
    def __init__(self, *args, **kwargs): 
     for name, field in self.fields.iteritems(): 
      field.widget = field.hidden_widget() 
      field.required = False 


class SlideForm(ModelForm): 
    class Meta: 
     model = Slide 


class HiddenSlideForm(SlideForm, HiddenFormMixin): 
    pass 


class DeckForm(ModelForm):  
    def __init__(self, *args, **kwargs): 
     # do some stuff here 
     return super(DeckForm, self).__init__(*args, **kwargs) 

    class Meta: 
     model = Deck 
     # other stuff here 


class HiddenDeckForm(DeckForm, HiddenFormMixin): 
    pass 

請注意,如果您在這兩個類別覆蓋__init__這可能不是直接的工作。在這種情況下,你可以這樣做來指定順序:

class HiddenDeckForm(DeckForm, HiddenFormMixin): 
    def __init__(self, *args, **kwargs): 
     # do some stuff here 
     DeckForm.__init__(self, *args, **kwargs) 
     HiddenFormMixin.__init__(self, *args, **kwargs) 
+2

嗯...不完全。在這種情況下,您需要調用'super',特別是在用於覆蓋特殊方法的mixin類時。 – SingleNegationElimination 2011-05-19 01:46:53

相關問題