【问题标题】:How to call super of enclosing class in a mixin in Python?python - 如何在Python的mixin中调用封闭类的super?
【发布时间】:2016-09-08 16:04:41
【问题描述】:

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

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

问题是,我应该在 mixin 中添加什么来确保它执行 B 并且不会阻止 Stuff A 的发生?

【问题讨论】:

  • 你确定继承顺序是正确的吗 - 你通常会在 父级之后放置一个 mixin...
  • 我不确定,不。我的理解是,如果我反过来做,mixin 的保存方法将被 Parent 覆盖。对吗?
  • 否 - MRO 是(对于非钻石继承) - 从右到左...
  • 已修复。把 cmets 留在里面。
  • 别理我——我能把它归结为缺乏咖啡吗? :p

标签: python django


【解决方案1】:

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

【讨论】:

  • 这很烦人的是大多数 IDE 会突出显示 MyMixinsuper(...).test() 调用,因为从技术上讲,MixMixin 上没有父类可以调用 test()
  • @jlh 我完全明白了,代码检查器上没有那个绿色复选标记真是令人讨厌。
  • 你能解释一下 super() 方法在没有父类的类中指的是什么吗?
【解决方案2】:

Django 示例(Python 3+)

要在 Django 上下文中扩展 Vladimir Prudnikov's answer,模板视图 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)

【讨论】:

    【解决方案3】:

    @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) 调用

    【讨论】:

      【解决方案4】:

      从超类调用实现的最佳实践是使用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 (Method Resolution Order)。从 MRO Python 决定在super() 调用上做什么。您可以通过这种方式查看您的班级的 MRO:

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

      所以,A 的超级是 ParentParent 的超级是 ModelModel 的超级是 MixinMixin 的超级是 object

      这是错误的,所以你应该把A的父母改成:

      class A(Mixin, Parent):
      

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

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

      【讨论】:

        猜你喜欢
        • 2010-11-24
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2017-06-30
        • 1970-01-01
        • 2018-07-25
        • 2022-01-19
        • 2018-05-27
        相关资源
        最近更新 更多