混入(mixins)的顺序如何影响派生类?

68

假设我有以下的混合器,它们之间通过接触dispatch()产生了重叠:

class FooMixin(object):
    def dispatch(self, *args, **kwargs):
        # perform check A
        ...
        return super(FooMixin, self).dispatch(*args, **kwargs)

class BarMixin(object):
    def dispatch(self, *args, **kwargs):
        # perform check B
        ...
        return super(FooMixin, self).dispatch(*args, **kwargs)
如果我想让视图按照A检查 -> B检查的顺序进行,我的代码应该是MyView(FooMixin, BarMixin, View)还是MyView(BarMixin, FooMixin, View)
为什么我们总是把View或其子类放在混合类后面?(我注意到这一点是从阅读Django通用视图的源代码中发现的,但我不知道背后的原理,如果有的话)
1个回答

107

MRO基本上是深度优先,从左到右。请参阅Method Resolution Order (MRO) in new style Python classes以获取更多信息。

您可以查看类的__mro__属性进行检查,但如果希望首先执行“check A”,则FooMixin应该排在第一位。

class UltimateBase(object):
    def dispatch(self, *args, **kwargs):
        print 'base dispatch'

class FooMixin(object):
    def dispatch(self, *args, **kwargs):
        print 'perform check A'
        return super(FooMixin, self).dispatch(*args, **kwargs)

class BarMixin(object):
    def dispatch(self, *args, **kwargs):
        print 'perform check B'
        return super(BarMixin, self).dispatch(*args, **kwargs)

class FooBar(FooMixin, BarMixin, UltimateBase):
    pass

FooBar().dispatch()

输出:

perform check A
perform check B
base dispatch
View必须放在最后,这样它才能“捕获”任何未在混合类上查找的属性查找,而不会隐藏那些混合类上的方法。我不确定我是否理解你问题的这一部分——是“为什么要添加它”还是“为什么要将其添加到最后”?

2
谢谢您的回答,我的问题实际上是想问为什么它被添加到最后面的,您已经解答了我的疑惑。感谢。 - tamakisquare
4
为了明确起见,这里直接调用的唯一方法是 FooMixin.dispatch。然后,super(FooMixin, self).dispatch 的结果为 BarMixin.dispatch,因为 object 没有 dispatch 方法。同样的,super(BarMixin, self).dispatch 由于同样的原因,其结果为 UltimateBase.dispatch - Mad Physicist
@MadPhysicist 这不是完全正确的。即使该方法也是由对象定义的,这也可以工作 - 请自行尝试。有关更多信息,请参见链接的答案。 - agf
@agf。当然。我的错误。object的分派将会被最后调用。我的陈述实际上应该是一个问题,但我分心了,忘记明确说明了。无论如何,感谢您的回答 :) - Mad Physicist

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接