关于python:python3中具有不同签名的多重继承

Multiple inheritance in python3 with different signatures

我有三个班:ABC

C继承自AB(按此顺序)。AB的构造函数签名不同。如何调用两个父类的__init__方法?

我的代码努力:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
class A(object):
    def __init__(self, a, b):
        super(A, self).__init__()
        print('Init {} with arguments {}'.format(self.__class__.__name__, (a, b)))

class B(object):
    def __init__(self, q):
        super(B, self).__init__()
        print('Init {} with arguments {}'.format(self.__class__.__name__, (q)))

class C(A, B):
    def __init__(self):
        super(A, self).__init__(1, 2)
        super(B, self).__init__(3)

c = C()

产生错误:

1
2
3
4
5
6
Traceback (most recent call last):
  File"test.py", line 16, in <module>
    c = C()
  File"test.py", line 13, in __init__
    super(A, self).__init__(1, 2)
TypeError: __init__() takes 2 positional arguments but 3 were given

我发现了这个资源,它用不同的参数组解释了多个继承,但是他们建议使用*args**kwargs来解释所有的参数。我认为这很难看,因为从子类中的构造函数调用中看不到我传递给父类的是什么类型的参数。


除非你知道自己在做什么,否则不要使用super(baseclass, ...)super()的第一个参数告诉它在寻找下一个要使用的方法时要跳过什么类。例如,super(A, ...)会查看MRO,找到A,然后开始在下一个基类上查找__init__,而不是A。对于C,mro是(C, A, B, object),所以super(A, self).__init__会找到B.__init__

对于这些情况,您不希望使用合作继承,而是直接引用A.__init__B.__init__。只有当您调用的方法具有相同的签名或将吞下不支持的参数时,才应使用super(),这些参数与*args**vargs相同。在这种情况下,只需要一个super(C, self).__init__()调用,MRO订单中的下一个类将负责链接调用。

换一种说法:当您使用super()时,您不知道MRO中的下一个类是什么,这样类更好地支持您传递给它的参数。如果不是这样,不要使用super()

直接调用基__init__方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
class A(object):
    def __init__(self, a, b):
        print('Init {} with arguments {}'.format(self.__class__.__name__, (a, b)))

class B(object):
    def __init__(self, q):
        print('Init {} with arguments {}'.format(self.__class__.__name__, (q)))

class C(A, B):
    def __init__(self):
        # Unbound functions, so pass in self explicitly
        A.__init__(self, 1, 2)
        B.__init__(self, 3)

使用合作super()

1
2
3
4
5
6
7
8
9
10
11
12
13
class A(object):
    def __init__(self, a=None, b=None, *args, **kwargs):
        super().__init__(*args, **kwargs)
        print('Init {} with arguments {}'.format(self.__class__.__name__, (a, b)))

class B(object):
    def __init__(self, q=None, *args, **kwargs):
        super().__init__(*args, **kwargs)
        print('Init {} with arguments {}'.format(self.__class__.__name__, (q)))

class C(A, B):
    def __init__(self):
        super().__init__(a=1, b=2, q=3)