如何将函数的重写普遍应用于 python 中的多个类?

发布于 2024-11-08 11:19:44 字数 1311 浏览 0 评论 0原文

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

I am working on a Django application but this seems like it is just a python question, with nothing necessarily specific to Django. I'm pretty new to python, and its hard to describe what I am trying to do, but easier to show so here goes:

I have one class:

class SlideForm(ModelForm):

    class Meta:
        model = Slide

which I subclass:

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

and then I have another class:

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  

which I also sub-class:

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

Note that the subclasses have the exact same code other than class names and do the exact same thing. I have been trying to figure what the best way to genericize this so I can keep it DRY and easily use it for other classes, and have considered decorators and/or multiple inheritance--both of which are new concepts for me--but I keep getting mixed up.

Help is appreciated!

(As a side note, feel free to point out any problems you see in my django code :) )

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

双手揣兜 2024-11-15 11:19:44

一种选择是使用 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 时,您就会遇到问题。在这种情况下,必须最后调用被重写的方法,这一点非常重要,因为一旦调用它,就不会再进行任何调用。

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

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

基类和以前一样,但由于所有公共代码都来自 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 位于继承图中的某个位置。否则可能会发生奇怪的事情。

One option is to use a Mixin class; example:

First, the common behavior goes in the 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

To the extent that you are in reasonable control of all of the classes in the inheritance graph, and so long as you call super in every method that needs to be overridden, then it doesn't matter too much what the derived classes look like.

However, you run into a problem when one of the superclasses does not itself call super at the correct time. It's very important that the overridden method, in that case, must be called last, since once it's called, no more calls will be made.

The simplest solution is to make sure that each class actually derives from the offending superclass, but in some cases, that's just not possible; deriving a new class creates a new object that you don't actually want to exist! Another reason might be because the logical base class is too far up the inheritance tree to work out. \

In that case, you need to pay particular attention to the order in which base classes are listed. Python will consider the left-most superclass first, unless a more derived class is present in the inheritance diagram. This is an involved topic, and to understand what python is really up to, you should read about the C3 MRO algorithm present in python 2.3 and later.

Base classes as before, but since all of the common code comes from the mixin, the derived classes become trivial

class HiddenSlideForm(SomeMixin, SlideForm):
    pass

class HiddenDeckForm(SomeMixin, DeckForm):
    pass

Note that the mixin class appears first, since we can't control what the *Form classes do in their init methods.

If the __init__ methods of either are non-trivial, you still get a win.

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

Make sure that object is in the inheritance diagram, somewhere. Strange things can happen otherwise.

阳光①夏 2024-11-15 11:19:44

多重继承(具体来说,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)

Multiple inheritance (specifically, Mixins) would probably be the best solution here.

Example:

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

Do note that this might not work directly if you overwrite __init__ in both classes. In that case you could do something like this to specify the order:

class HiddenDeckForm(DeckForm, HiddenFormMixin):
    def __init__(self, *args, **kwargs):
        # do some stuff here
        DeckForm.__init__(self, *args, **kwargs)
        HiddenFormMixin.__init__(self, *args, **kwargs)
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文