关于类:Python调用父方法多重继承

Python Call Parent Method Multiple Inheritance

所以,我遇到了这样的情况。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
class A(object):
    def foo(self, call_from):
        print"foo from A, call from %s" % call_from


class B(object):
    def foo(self, call_from):
        print"foo from B, call from %s" % call_from


class C(object):
    def foo(self, call_from):
        print"foo from C, call from %s" % call_from


class D(A, B, C):
    def foo(self):
        print"foo from D"
        super(D, self).foo("D")

d = D()
d.foo()

代码的结果是

1
2
foo from D
foo from A, call from D

我想从D类调用所有父方法,在本例中是foo方法,而不在A之类的父类上使用super。我只想打电话给D班的学生。ABC类就像mixin类,我想从D调用所有foo方法。我怎样才能做到这一点?


在除C以外的其他类中也添加super()调用。因为D的MRO是

1
2
>>> D.__mro__
(<class '__main__.D'>, <class '__main__.A'>, <class '__main__.B'>, <class '__main__.C'>, <type 'object'>)

你不需要在C中使用super call。

代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
class A(object):
    def foo(self, call_from):
        print"foo from A, call from %s" % call_from
        super(A,self).foo('A')

class B(object):
    def foo(self, call_from):
        print"foo from B, call from %s" % call_from
        super(B, self).foo('B')


class C(object):
    def foo(self, call_from):
        print"foo from C, call from %s" % call_from

class D(A, B, C):
    def foo(self):
        print"foo from D"
        super(D, self).foo("D")

d = D()
d.foo()

输出:

1
2
3
4
foo from D
foo from A, call from D
foo from B, call from A
foo from C, call from B


你可以这样使用__bases__

1
2
3
4
5
class D(A, B, C):
    def foo(self):
        print"foo from D"
        for cls in D.__bases__:
            cls().foo("D")

随着这一变化,输出将

1
2
3
4
foo from D
foo from A, call from D
foo from B, call from D
foo from C, call from D


我认为,在子类中调用super是一种更为Python式的方法。不必使用父类名称(特别是在super中)。在前面的示例中,这里有一些应该可以工作的代码(python 3.6+):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
class A:
    def foo(self, call_from):
        print(f"foo from A, call from {call_from}")
        super().foo('A')

class B:
    def foo(self, call_from):
        print(f"foo from B, call from {call_from}")
        super().foo('B')


class C(object):
    def foo(self, call_from):
        print(f"foo from C, call from {call_from}")
        super().foo('C')

class StopFoo:
    def foo(self, call_from):
        pass

class D(A, B, C, StopFoo):
    def foo(self, call_from):
        print(f"foo from D, call from {call_from}")
        super().foo('D')

如果运行此代码:

1
2
d = D()
d.foo('D')

你会得到:

1
2
3
4
foo from D, call from D
foo from A, call from D
foo from B, call from A
foo from C, call from B

这种策略的优点是,只要包含StopFoo类,就不必为继承顺序操心。这个有点特别,可能不是完成这项任务的最佳策略。基本上,继承树中的每个类都调用foo方法,并调用父方法,这样做也是一样的。我们可能在讨论多重继承,但继承树实际上是平的(d->a->b->c->stopfoo->object)。我们可以更改继承顺序,向这个模式添加新的类,删除它们,只需调用一个类…但技巧仍然存在:在调用foo离开我们定义的类之前,包括StopFoo

对于带有钩子的混合模式,这可能是有意义的。但是,当然,解决方案在每种情况下也没有那么有用。不要害怕super,尽管它有很多技巧,并且在简单和多继承中非常有用,可以使用mixin或简单的抽象类。