简体   繁体   English

如何在 Python 的 mixin 中调用封闭类的超级?

[英]How to call super of enclosing class in a mixin in Python?

I have the following code, in Django:我在 Django 中有以下代码:

class Parent(models.Model):
    def save(self):
        # Do Stuff A

class Mixin(object):
    def save(self):
        # Do Stuff B

class A(Parent, Mixin):
    def save(self):
        super(A, self).save()
        # Do stuff C

Now, I want to use the mixin without blatting the behaviour of the save in Parent.现在,我想在不破坏父级保存行为的情况下使用 mixin。 So I when I save, I want to do stuff C, B, and A. I've read Calling the setter of a super class in a mixin however I don't get it and having read the super docs it doesn't seem to answer my question.因此,当我保存时,我想做 C、B 和 A 的事情。我已经阅读了在 mixin 中调用超类的 setter但是我不明白并且阅读了超级文档似乎没有回答我的问题。

THe question is, what do I put in the mixin to make sure it does stuff B and doesn't stop Stuff A from happening?问题是,我在 mixin 中放了什么来确保它执行 B 并且不会阻止 A 发生?

How about calling super in your mixin class?在你的 mixin 类中调用 super 怎么样?

class Parent(object):
    def test(self):
        print("parent")


class MyMixin(object):
    def test(self):
        super(MyMixin, self).test()
        print("mixin")


class MyClass(MyMixin, Parent):
    def test(self):
        super(MyClass, self).test()
        print("self")

if __name__ == "__main__":
    my_obj = MyClass()
    my_obj.test()

This will give you the output as:这将为您提供如下输出:

$ python test.py
parent
mixin
self

The best practice for calling the implementation from the superclass is to use super() :从超类调用实现的最佳实践是使用super()

class Mixin(object):
    def save(self):
        super(Mixin, self).save()
        # Do Stuff B here or before super call, as you wish

What is important is that you call super() in each class (so that it propagates all the way) but not the topmost (base) class, because its superclass does not have save() .重要的是你在每个类中调用super() (以便它一直传播)而不是最顶层(基)类,因为它的超类没有save()

Note that when you call super(Mixin, self).save() , you don't really know what the super class would be once it is executed.请注意,当您调用super(Mixin, self).save() ,您实际上并不知道超类在执行后会是什么。 That will be defined later.这将在稍后定义。

Unlike some other languages, in python, the end class will always have a linear list of classes from which it inherits.与其他一些语言不同,在 python 中,最终类将始终具有它继承的类的线性列表。 That is called MRO ( Method Resolution Order ).这称为 MRO(方法解析顺序)。 From MRO Python decides what to do on super() call.从 MRO Python 决定在super()调用上做什么。 You can see what the MRO is for your class this way:您可以通过这种方式查看 MRO 对您的班级的意义:

>>> A.__mro__
(<class '__main__.A'>, <class '__main__.Parent'>, <class '__main__.Model'>, <class '__main__.Mixin'>, <type 'object'>)

So, A 's super is Parent , Parent 's super is Model , Model 's super is Mixin and Mixin 's super is object .所以, A的 super 是ParentParent的 super 是ModelModel的 super 是MixinMixin的 super 是object

That is wrong, so you should change A 's parents to:这是错误的,因此您应该将A的父母更改为:

class A(Mixin, Parent):

Then you'd have a better MRO:那么你会有一个更好的 MRO:

>>> A.__mro__
(<class '__main__.A'>, <class '__main__.Mixin'>, <class '__main__.Parent'>, <class '__main__.Model'>, <type 'object'>)

@Click2Death answer is correct, however, when you call super().test() inside your mixin class most IDE will claim that test is unresolved, which is correct. @Click2Death 答案是正确的,但是,当您在 mixin 类中调用super().test()大多数 IDE 会声称test未解决,这是正确的。

在此处输入图片说明

Here is how to make your IDE happy and your code better.以下是如何让您的 IDE 满意并让您的代码更好。

class Parent(object):
    def test(self):
        print("parent")


class MyMixin(object):
    def test(self):
        super_test = getattr(super(), 'test')
        if super_test and callable(super_test):
            super_test()
        print("mixin")


class MyClass(MyMixin, Parent):
    def test(self):
        super().test()
        print("self")

if __name__ == "__main__":
    my_obj = MyClass()
    my_obj.test()

This is Python 3 code, to make it working with Python 2 you need to pass two arguments to the super(MyClass, self) call这是 Python 3 代码,要使其与 Python 2 一起使用,您需要将两个参数传递给super(MyClass, self)调用

Django Example (Python 3+) Django 示例(Python 3+)

To expand on Vladimir Prudnikov's answer in a Django context, the template view mixin class could be structured as shown below.为了在 Django 上下文中扩展Vladimir Prudnikov 的回答,模板视图 mixin 类的结构可以如下所示。

from django.views.generic.base import View


class MyViewMixin:

    def dispatch(self, request, *args, **kwargs):
        super_dispatch = getattr(super(), 'dispatch')
        if super_dispatch and callable(super_dispatch):
            return super_dispatch(request, *args, **kwargs)
        raise RuntimeError('MyViewMixin must be used as part of a '
            'multiple inheritance chain that includes a Django template-view')


class MyCustomView(MyViewMixin, View):

    def dispatch(self, *args, **kwargs):
        return super().dispatch(*args, **kwargs)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM