繁体   English   中英

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

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

我在 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

现在,我想在不破坏父级保存行为的情况下使用 mixin。 因此,当我保存时,我想做 C、B 和 A 的事情。我已经阅读了在 mixin 中调用超类的 setter但是我不明白并且阅读了超级文档似乎没有回答我的问题。

问题是,我在 mixin 中放了什么来确保它执行 B 并且不会阻止 A 发生?

在你的 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()

这将为您提供如下输出:

$ python test.py
parent
mixin
self

从超类调用实现的最佳实践是使用super()

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

重要的是你在每个类中调用super() (以便它一直传播)而不是最顶层(基)类,因为它的超类没有save()

请注意,当您调用super(Mixin, self).save() ,您实际上并不知道超类在执行后会是什么。 这将在稍后定义。

与其他一些语言不同,在 python 中,最终类将始终具有它继承的类的线性列表。 这称为 MRO(方法解析顺序)。 从 MRO Python 决定在super()调用上做什么。 您可以通过这种方式查看 MRO 对您的班级的意义:

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

所以, A的 super 是ParentParent的 super 是ModelModel的 super 是MixinMixin的 super 是object

这是错误的,因此您应该将A的父母更改为:

class A(Mixin, Parent):

那么你会有一个更好的 MRO:

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

@Click2Death 答案是正确的,但是,当您在 mixin 类中调用super().test()大多数 IDE 会声称test未解决,这是正确的。

在此处输入图片说明

以下是如何让您的 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()

这是 Python 3 代码,要使其与 Python 2 一起使用,您需要将两个参数传递给super(MyClass, self)调用

Django 示例(Python 3+)

为了在 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