多继承

除了从一个父类继承外,Python允许从多个父类继承,称为多重继承。
多继承格式

1
2
class 子类(父类1,父类2,...):
    pass

例如,下面类C继承类A和类B。

1
2
3
4
5
6
7
8
class A:
    pass

class B:
    pass

class C(A,B):
    pass

多继承MRO问题

MRO即method resolution order,方法解析顺序,用于判断子类调用的属性来自于哪个父类。类C继承自父类A和B,调用C的属性时,是调用A的属性还是B的属性。通过类的mro属性,可以解决此问题。

mro属性

此属性是在方法解析期间查找基类的元组。此属性引入的目的主要是为了解决查找顺序(MRO)的问题。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
class A:
    pass

class B:
    pass

class C(A,B):
    pass

print(A.__mro__)
print(B.__mro__)
print(C.__mro__)

执行以上程序会输出如下结果:

1
2
3
(<class '__main__.A'>, <class 'object'>)
(<class '__main__.B'>, <class 'object'>)
(<class '__main__.C'>, <class '__main__.A'>, <class '__main__.B'>, <class 'object'>)

从上面可以看出,类C首先查找本身,如果没有的话,再查找父类A,没有的话,查找父类B,最后查找object。

例如

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
class A:
    attrA = "Attr A"
    name = "Class Name"

class B:
    attrB = "Attr B"

class C(A,B):
    attrC = "Attr C"

C.attrB  #首先在类C本身查找属性attrB。不存在,接着在类A中查找属性attrB。也不存在,在类B中查找属性attrB,找到了
C.attrA  #首先在类C本身查找属性attrA。不存在,接着在类A中查找属性attrA。找到了
C.attrC  #首先在类C本身查找属性attrC,找到了
C.name   #首先在类C本身查找属性name。不存在,接着在类A中查找属性name。找到了

base属性

此属性用来记录类的父类。有多个父类时,返回第一个。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
class A:
    pass

class B:
    pass

class C(A,B):
    pass

print(A.__base__)  # 打印A的父类
print(B.__base__)  # 打印B的父类
print(C.__base__)  # 打印C的父类

执行以上程序会输出如下结果:

1
2
3
<class 'object'>
<class 'object'>
<class '__main__.A'>

如果C的类继承顺序更改为先B后A。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
class A:
    pass

class B:
    pass

class C(B,A):
    pass

print(A.__base__)  #打印A的父类
print(B.__base__)  #打印B的父类
print(C.__base__)  #打印C的父类

执行以上程序会输出如下结果:

1
2
3
<class 'object'>
<class 'object'>
<class '__main__.B'>

bases

此属性用来记录类对象的基类的元组。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
class A:
    pass

class B:
    pass

class C(A,B):
    pass

print(A.__bases__)
print(B.__bases__)
print(C.__bases__)

执行以上程序会输出如下结果:

1
2
3
(<class 'object'>,)
(<class 'object'>,)
(<class '__main__.A'>, <class '__main__.B'>)

如果C的类继承顺序更改为先B后A。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
class A:
    pass

class B:
    pass

class C(B,A):
    pass

print(A.__bases__)
print(B.__bases__)
print(C.__bases__)

执行以上程序会输出如下结果:

1
2
3
(<class 'object'>,)
(<class 'object'>,)
(<class '__main__.B'>, <class '__main__.A'>)

多继承钻石问题(也叫菱形问题)

如果子类继承自两个单独的父类,而那两个父类又继承自同一个公共基类,那么就构成了钻石继承体系。这种继承体系很像竖立的菱形,也称作菱形继承。

插入图片

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
class A:
    def __init__(self, value):
        self.value = value

class B(A):
    def __init__(self, value):
        A.__init__(self, value)
        self.value += 2

class C(A):
    def __init__(self, value):
        A.__init__(self, value)
        self.value += 3

class D(B, C):
    def __init__(self, value):
        B.__init__(self, value)
        C.__init__(self, value)

d = D(1)
print(d.value)  #结果是4,而不是6

为啥结果不是6呢。因为在调用第二个超类时,即C.__init__,它会再次调用A.__init__,从而导致self.value重新变成1。

解决这个问题的方式是使用super方法,根据方法解析顺序(MRO)以标准化的流程来安排超类之间的初始化顺序,它也能够保证钻石顶部的公共基类的init方法之运行一次。

修改如下

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
class A:
    def __init__(self, value):
        self.value = value

class B(A):
    def __init__(self, value):
        super().__init__(value + 2)

class C(A):
    def __init__(self, value):
        super().__init__(value + 3)

class D(B, C):
    def __init__(self, value):
        super().__init__(value)

d = D(1)
print(d.value)   # 结果6

super()函数和init()函数

既然super()函数和init()函数都是初始化类的,他们之间有什么异同呢。

相同点
都是用于初始化类的,单继承时super()和init()实现的功能是类似的。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
class Base:
    def __init__(self):
        print('Base create')

class childA(Base):
    def __init__(self):
        print('creat A')
        Base.__init__(self)

class childB(Base):
    def __init__(self):
        print('creat B')
        super().__init__()

base = Base()
a = childA()
b = childB()

执行以上程序会输出如下结果:

1
2
3
4
5
Base create
creat A
Base create
creat B
Base create

不同点
super是用来解决多重继承问题的,直接用类名调用父类方法在使用单继承的时候没问题,但是如果使用多继承,会涉及到查找顺序(MRO)、重复调用(钻石继承)等种种问题。多重继承请使用super().xxx。

语法
super(type[, object-or-type])
参数
type – 类。
object-or-type – 类,一般是self
Python3.x和Python2.x的一个区别是: Python3直接使用super().xxx 代替super(Class, self).xxx。

Python3.x 实例:

1
2
3
4
5
class A:
    pass
class B(A):
    def add(self, x):
        super().add(x)

Python2.x 实例:

1
2
3
4
5
class A(object):   # Python2.x 记得继承 object
    pass
class B(A):
    def add(self, x):
        super(B, self).add(x)

转载请注明本网址。