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

Ben*_*rts 5 python django inheritance decorator

我正在研究一个Django应用程序,但这似乎只是一个python问题,没有必要特定于Django.我是python的新手,很难描述我想要做什么,但更容易展示,所以这里:

我有一节课:

class SlideForm(ModelForm):

    class Meta:
        model = Slide
Run Code Online (Sandbox Code Playgroud)

我的子类:

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
Run Code Online (Sandbox Code Playgroud)

然后我又上了一堂课:

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  
Run Code Online (Sandbox Code Playgroud)

其中我也分类:

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
Run Code Online (Sandbox Code Playgroud)

请注意,子类具有与类名称完全相同的代码,并执行完全相同的操作.我一直在试图弄清楚什么是最好的通用化方法,所以我可以保持干燥并轻松地将它用于其他类,并考虑装饰器和/或多重继承 - 这两个对我来说都是新概念 - 但我不断变得混乱.

感谢帮助!

(作为旁注,请随时指出您在我的django代码中看到的任何问题:))

Sin*_*ion 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
Run Code Online (Sandbox Code Playgroud)

如果您能够合理控制继承图中的所有类,并且只要您调用super需要重写的每个方法,那么派生类的外观并不重要。

但是,当超类之一本身没有super在正确的时间调用时,您就会遇到问题。在这种情况下,必须最后调用被重写的方法,这一点非常重要,因为一旦调用它,就不会再进行任何调用。

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

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

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

class HiddenSlideForm(SomeMixin, SlideForm):
    pass

class HiddenDeckForm(SomeMixin, DeckForm):
    pass
Run Code Online (Sandbox Code Playgroud)

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

如果__init__这两种方法都非常重要,那么您仍然会获胜。

class HiddenSlideForm(SomeMixin, SlideForm):
    def __init__(self, *args, **kwargs):
        super(HiddenSlideForm, self).__init__(*args, **kwargs)
        do_something_special()
Run Code Online (Sandbox Code Playgroud)

确保它object位于继承图中的某个位置。否则可能会发生奇怪的事情。

  • 谢谢回复!我确实继承了 Django 提供的基类(ModelForm),但你的代码对我不起作用。Mixin 中的 init 函数永远不会被调用。这是一个简单的测试用例,演示了发生的情况:http://pastebin.com/a1tnXsjA。知道解决办法是什么吗?(顺便说一句,我使用的是Python 2.6) (2认同)