请稍候,加载中....

类的多重继承

Python语言中,要实现类的多重继承,只要在定义类的时候,在圆括号中以逗号分隔多个父类即可

# Python支持多重继承,也就是一个类可以从多个基类那里继承属性
# class ChildClass(ParentClass1,ParentClass2...):
#          pass

Python多重继承举例

# 父类1 - 人类
class Person:
    def __init__(self, name, sex, age):
        self._name = name
        self._sex = sex
        self._age = age
# 父类2 - 程序员类
class Programer:
    def work(self):
        self._work()

    def _work(self):
        print("coding and coding, day by day!")
# Python程序员类
# 从Person类继承_name,_age
# 从Programer类继承work

class Pythonor(Person, Programer):
    def _work(self):
        print(f"{self._name} has been coding {self._age} years in python world") 

# 实例化
luxp = Pythonor("老六", "男", 28)
luxp.work()

从上面这个例子中可以看到 Pythoner类继承自Person类及Programer类,当实例化的时候,执行的是Person类的__init__方法,work()则是Programer类的方法

多重继承的顺序

我们不难想到,如果一个类继承的父类,都包含着一个同名的方法,那么当子类执行父类该方法时,应该继承谁的?

多重继承顺序举例

class A:
    def do(self):
        print("A")


class B:
    def do(self):
        print("B")

class C(A,B):
    pass

c = C()
c.do()
# 输出 A

# D调整了继承顺序
class D(B,A):
    pass

d = D()
d.do()
# 输出B
# 继承顺序是从左到右搜索,一旦搜索到方法后停止搜索

由此类可见,继承顺序是从左到右搜索,一旦搜索到方法后停止搜索

更复杂一点的多重继承

# 更加复杂的多重继承
class A:
    def do(self):
        print("A")

class B:
    def do(self):
        print("B")

class C(A):
    pass


class D(B):
    def do(self):
        print("D")

class E(C,D):
    pass

e = E()
e.do()
# 输出 A

在这个例子中, E类继承自C类、D类,C类继承自A类,D类继承自B类,C类没有do方法,D类有do方法,然而最后输出的是A,这说明E类在寻找继承方法的时候,是从左开始,然后顺着左侧的继承树往上查找,直到找到,如果找不到,就会往右找,这种规则就是:

  • 广度优先 - 先从左往右开始
  • 深度优先 - 从某一侧往父级方向查找,直到这一侧遍历完成,再向右侧查找

菱形继承

就是类的多个父类继承自同一个父类,这样形成一个菱形,比如所有的类都是来自object

class GrandpaClass:
    def do(self):
        self._show_me()

        def _show_me(self):
            print(self.__class__)


class FatherClass(GrandpaClass):
    pass


class UncleClass(GrandpaClass):
    def _show_me(self):
        print("hello, class name is", self.__class__)


class ChildClass(FatherClass, UncleClass):
    pass

zhangsan = ChildClass()
zhangsan.do()

__mro__  - 顺序线性化

实际上,类的方法继承顺序是动态的,因为多重继承带来的复杂性可能超出了想象,如果每一次都要人为的去考虑继承顺序,会给编程工作带来很大困扰,Python的多重继承事实采用了一种叫C3的算法,从而将各种继承顺序以线性顺序的方法表达出来,可以通过类属性__mro__查看

# __mro__提供了一个元组序列,该序列反映了继承顺序
print(E.__mro__)
# 输出
# (__main__.E, __main__.C, __main__.A, __main__.D, __main__.B, object)
print(ChildClass.__mro__)

super-获得超类的方法

# super([type[, object-or-type]])

super返回一个代理对象,它会将方法调用委托给 type 指定的父类或兄弟类,指定的顺序依据__mro__属性
如果不带任何参数,则将方法绑定到默认的第一个父类
如果传参, 第二个参数必须是第一个参数的实例或者子类, 然后方法按照__mro__顺序绑定到type之后的某个类

单继承中的super用法

假设子类中有__init__方法,同时又需要执行父类的__init__方法,如果不使用super,代码如下

class Person:
    def __init__(self, name, age, sex):
        self._name = name
        self._age = age
        self._sex = sex
    def show(self):
        print(f"name:{self._name}, age:{self._age}, sex:{self._sex}")

class Man(Person):
     __sex = "MAN"
     def __init__(self, name, age):

         # 调用父类的__init__方法
         Person.__init__(self, name, age, self.__sex)


zhangsan = Man("zhangsan", 28)
zhangsan.show()

Man类中__init__方法中通过Person.__init__的方式执行了父类的__init__,需要注意的是传入了参数self

super()使用举例

# 使用super执行父类方法
class Woman(Person):
     __sex = "WOMAN"
     def __init__(self, name, age):
         super().__init__(name, age, self.__sex)

cuihua = Woman("cuihua", 18)
cuihua.show()

这里使用了super().__init__方式,没有传入self参数,这种方式可以防止父类改名引起的不必要的麻烦:如果多处使用父类方法,就需要修改多处

多重继承中使用super举例

在多继承中可以通过向super传入参数来限制继承搜索路径

class A:
    def show(self):
        print(A)

class B:
    def show(self):
        print(B)

class C(A):
    def show(self):
        print(C)

class D(B):
    def show(self):
        print(D)

class E(C, D):
    def show(self):
        print(E.__mro__)
        super().show()
        print("*"*10)
        super(A, self).show()


e = E()
e.show()
# 输出
# mro顺序
# (<class '__main__.E'>, <class '__main__.C'>, <class '__main__.A'>, <class '__main__.D'>, <class '__main__.B'>, <class 'object'>)
# super().show()
# <class '__main__.C'>
# super(A,self).show()
# <class '__main__.D'>

# super的第一个参数改为C
class E(C, D):
    def show(self):
        print(E.__mro__)
        super().show()
        print("*"*10)
        super(C, self).show()

e = E()
e.show()

# 当super传入相应参数的时候,可以在类外部使用
super(C, e).show()

super(A,self)得到的是D类,从mro顺序中可以看到A后面的是D


Python学习手册-