如何一般性地将一个函数的覆盖应用于python中的多个类?
我正在研究一个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的代码:)你看任何问题)
一个选项是使用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
是在继承图,某处。奇怪的事情可能会发生,否则。
感谢您的回复!我从Django提供的基类继承(ModelForm),但是你的代码对我不起作用。 Mixin中的init函数永远不会被调用。以下是一个简单的测试案例,演示发生了什么:http://pastebin.com/a1tnXsjA。任何想法是什么修复? (顺便说一句,我在Python 2.6) – 2011-05-19 07:17:22
而不是使用超级,只需在'HiddenSlideForm .__ init __()'中明确(一个接一个地)调用'SomeMixin'和'SlideForm'的'__init __()'。 – Imran 2011-05-20 07:11:54
Imram,尽管这并不理想,因为我将不得不在每个子类中编写一个init,但它看起来可能是实现它的方法,因为其他建议的用于使用Mixin自动执行覆盖的想法不会似乎工作。如果您创建了评论的答案形式版本,我会将其标记为已接受,因为它实际上可行。 – 2011-05-23 14:28:18
多重继承(具体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)
嗯...不完全。在这种情况下,您需要调用'super',特别是在用于覆盖特殊方法的mixin类时。 – SingleNegationElimination 2011-05-19 01:46:53
问题应该可能要求解决问题的方法,因此它不涉及在表单中嵌入大量隐藏字段? – 2011-05-19 01:55:18
谢谢你的建议,约翰。发布了一个单独的问题,描述了我正在使用的场景。 http://stackoverflow.com/questions/6054124。如果您有一些想法,请随时发布答案。我很想弄清楚如何以更清洁的方式实现这一点。 – 2011-05-19 05:23:09
+1用于查找我答案中的错误;现在我更了解python了! – SingleNegationElimination 2011-05-20 00:59:49