Python2.7和3的多重继承区别

Multiple inheritance difference between Python 2.7 and 3

我已经了解到 Python 2.7 和 3. 实现多重继承之间存在差异,例如:

在Python 3.:

class A:
    def __init__(self, x2='', x3='', **kwargs):
        print kwargs
        super().__init__(**kwargs)
        self.x2 = x2
        self.x3 = x3

class B:
    def __init__(self, x4='', x5='', **kwargs):
        print kwargs
        super().__init__(**kwargs)
        self.x4 = x4
        self.x5 = x5

class C(A, B):
    def __init__(self, x1='', **kwargs):
        print kwargs
        super().__init__(**kwargs)
        self.x1 = x1

并且在 Python 2.7 中:

class A(object):
    def __init__(self, x2='', x3='', **kwargs):
        print kwargs
        super(A, self).__init__(**kwargs)
        self.x2 = x2
        self.x3 = x3

class B(object):
    def __init__(self, x4='', x5='', **kwargs):
        print kwargs
        super(B, self).__init__(**kwargs)
        self.x4 = x4
        self.x5 = x5

class C(A, B):
    def __init__(self, x1='', **kwargs):
        print kwargs
        super(C, self).__init__(**kwargs)
        self.x1 = x1

运行代码:

C(x1='a',x2='b',x3='c',x4='d',x5='e',x6='f',x7='g')

在Python3.,我得到:

{'x2': 'b', 'x3': 'c', 'x6': 'f', 'x7': 'g', 'x4': 'd', 'x5': 'e'}
{'x6': 'f', 'x7': 'g', 'x4': 'd', 'x5': 'e'}
{'x6': 'f', 'x7': 'g'}

但照此操作,Python 2.76 也会报错:

{'x2': 'b', 'x3': 'c', 'x6': 'f', 'x7': 'g', 'x4': 'd', 'x5': 'e'}
{'x6': 'f', 'x7': 'g', 'x4': 'd', 'x5': 'e'}
{'x6': 'f', 'x7': 'g'}
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
super(C, self).__init__(**kwargs)
super(A, self).__init__(**kwargs)
super(B, self).__init__(**kwargs)
TypeError: object.__init__() takes no parameters

我注意到如果我从 Python 2.7 代码中删除 super(B, self).__init__(**kwargs),不会有任何错误,因为可能 class B 没有继承自 class A。任何人都知道在 Python 3 中这是如何毫无问题地工作的?以及 Python 2.7 中解决此问题的任何解决方案?

在你的继承树底部使用一个哨兵对象调用super().__init__():

class Sentinel(object):
    def __init__(self, **kw):
        pass

class A(Sentinel):
    def __init__(self, x2='', x3='', **kwargs):
        super(A, self).__init__(**kwargs)
        self.x2 = x2
        self.x3 = x3

class B(Sentinel):
    def __init__(self, x4='', x5='', **kwargs):
        super(B, self).__init__(**kwargs)
        self.x4 = x4
        self.x5 = x5

class C(A, B):
    def __init__(self, x1='', **kwargs):
        super(C, self).__init__(**kwargs)
        self.x1 = x1

这样 Sentinel.__init__ 总是最后调用而不是 object.__init__。通过这种方式,您可以确保所有 __init__ 方法始终接受相同的参数。

参见 Raymond Hettinger's super() considered super! article (or the PyCon presentation based on it)。