如何在python中将一个函数的重写一般应用于多个类?

时间:2011-05-19 01:04:19

标签: python django inheritance decorator

我正在研究一个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代码中看到的任何问题:))

2 个答案:

答案 0 :(得分:4)

一种选择是使用Mixin类;例如:

首先,常见的行为出现在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时,会遇到问题。在这种情况下,重写的方法必须被称为 last ,这一点非常重要,因为一旦调用它,就不会再进行调用。

最简单的解决方案是确保每个类实际上都来自有问题的超类,但在某些情况下,这是不可能的;派生一个新类创建一个你实际上不想存在的新对象!另一个原因可能是因为逻辑基类离继承树太远而无法解决。 \

在这种情况下,您需要特别注意列出基类的 order 。 Python将首先考虑最左边的超类,除非继承图中存在更多派生类。这是一个涉及的主题,为了理解python的真正含义,你应该阅读python 2.3及更高版本中的C3 MRO algorithm

基类与以前一样,但由于所有公共代码都来自mixin,派生类变得微不足道

class HiddenSlideForm(SomeMixin, SlideForm):
    pass

class HiddenDeckForm(SomeMixin, DeckForm):
    pass

请注意,mixin类首先出现 ,因为我们无法控制*Form类在其init方法中的作用。

如果任何一种__init__方法都不重要,那么你仍然可以获胜。

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

确保object在某个地方的继承图中。否则会发生奇怪的事情。

答案 1 :(得分: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)