How to generically apply an override of a function to mutiple classes in python?
我正在开发一个django应用程序,但这似乎只是一个python问题,没有任何特定于django的问题。我对python还很陌生,很难描述我想做什么,但更容易展示,下面是:
我有一个班:
1 2 3 4 | class SlideForm(ModelForm): class Meta: model = Slide |
我将其分为:
1 2 3 4 5 6 | 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 |
号
然后我又上了一节课:
1 2 3 4 5 6 7 8 9 | 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 |
我也分为以下几类:
1 2 3 4 5 6 7 | 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代码中看到的任何问题:)
一个选项是使用mixin类;示例:
首先,在mixin中常见的行为是:
1 2 3 4 5 6 | 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 |
在某种程度上,您可以合理地控制继承图中的所有类,只要您在需要重写的每个方法中调用
然而,当其中一个超类本身在正确的时间不称为
最简单的解决方案是确保每个类实际上是从有问题的超类派生的,但在某些情况下,这是不可能的;派生一个新类会创建一个您实际上不想存在的新对象!另一个原因可能是因为逻辑基类在继承树上太高,无法计算出来。
在这种情况下,您需要特别注意基类的列出顺序。除非继承关系图中存在更派生的类,否则python将首先考虑最左边的超类。这是一个涉及到的主题,为了理解Python真正在做什么,您应该阅读一下Python2.3和更高版本中的c3 mro算法。
基类和以前一样,但是由于所有公共代码都来自mixin,派生类变得微不足道。
1 2 3 4 5 | class HiddenSlideForm(SomeMixin, SlideForm): pass class HiddenDeckForm(SomeMixin, DeckForm): pass |
。
注意,mixin类首先出现,因为我们无法控制
如果任何一种方法的
1 2 3 4 | class HiddenSlideForm(SomeMixin, SlideForm): def __init__(self, *args, **kwargs): super(HiddenSlideForm, self).__init__(*args, **kwargs) do_something_special() |
确保
多重继承(特别是mixin)可能是这里最好的解决方案。
例子:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 | 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 |
请注意,如果在这两个类中都覆盖
1 2 3 4 5 | class HiddenDeckForm(DeckForm, HiddenFormMixin): def __init__(self, *args, **kwargs): # do some stuff here DeckForm.__init__(self, *args, **kwargs) HiddenFormMixin.__init__(self, *args, **kwargs) |
号