python面向对象-多继承

概述

继承在面向对象语言中,是最重要的概念之一,是为了让子类拥有父类的功能,达到代码重用的目的。在有的开发语言中,只能继承一个父类,如JAVA。

python同C++一样,可以继承多个父类

多继承

如上图:
子类可以 继承 多个父类,也就继承了 所有父类 的 属性 和 方法

语法:

class 类名( 父类1 , 父类2 ):
    pass

案例1

子类没有实现 __init__() 方法,只会执行 第一个父类的 __init__() 方法,所以 继承第一个父类的属性

代码

Phone类

class Phone:
    def __init__(self,cpu,ram,rom):
        self.cpu=cpu
        self.ram=ram
        self.rom=rom
        print(str(self.__class__)+" init")    
    def call(self,number):
        print("打电话给:%s"%number)
    def sms(self,number,message):
        print("发短信给:%s,消息:%s"%(number,message))

IntelligentDevice类

class IntelligentDevice:
    def __init__(self):
        print(str(self.__class__)+" init")    
    def install_app(self,app_name):
        print("安装 %s"%app_name)

    def uninstall_app(self,app_name):
        print("卸载 %s"%app_name)

SmartPhone类

class SmartPhone(Phone,IntelligentDevice):
    pass

创建 SmartPhone类对象(报错)

iphone=SmartPhone()

执行报错:

TypeError: __init__() missing 3 required positional arguments: 'cpu', 'ram', and 'rom'

原因:因为子类没有实现 __init__() 方法,会执行第一个父类(Phone)的 __init__() 方法,所以需要传入 cpu,ram,rom

正确创建 SmartPhone类对象

iphone=SmartPhone("A11","2G","64G")
print(iphone.cpu)
iphone.call("911")
iphone.sms("110","买了否了")
iphone.install_app("抖音")

小结

  1. 继承 所有父类的方法

  2. 如果子类没有实现 __init__() 方法,会执行第一个父类的 __init__() 方法。
    所以会 继承第一个父类 的实例属性

案例2

子类没有实现 __init__() 方法,只会执行第一个父类的 __init__() 方法,不会执行 第二个父类的 __init__() 方法,所以 不会继承第二个父类的属性

代码

修改 IntelligentDevice 类,在该类定义成员变量 apps(list类型),记录安装的app,代码如下:

class IntelligentDevice:
    def __init__(self):
        self.apps=[]
        print("IntelligentDevice __init__()") 

    def install_app(self,app_name):
        self.apps.append(app_name)
        print("安装 %s"%app_name)

    def uninstall_app(self,app_name):

        self.apps.remove(app_name)
        print("卸载 %s"%app_name)

问题

此时,像上例那样定义 SmartPhone 类,并调用就会报错

class SmartPhone(Phone,IntelligentDevice):
    pass

调用

iphone=SmartPhone("A11","2G","64G")
iphone.install_app("抖音")

执行结果如下:

AttributeError: 'SmartPhone' object has no attribute 'apps'

因为 SmartPhone 没有继承 IntelligentDevice 类的 apps 属性

没有继承apps属性的原因是:默认调用第一个父类的 __init__() 方法

子类定义__init__()方法

修改SmartPhone类,增加__init__()方法

class SmartPhone(Phone,IntelligentDevice):
    def __init__(self):
        super().__init__("A11","2G","64G")

调用

iphone=SmartPhone("A11","2G","64G")
iphone.install_app("抖音")

执行结果如下:

AttributeError: 'SmartPhone' object has no attribute 'apps'

解释:
如果子类实现了__init__()方法,就执行自己的__init__()方法。
要继承父类的实例属性,就要执行super().__init__()方法,调用 第一个父类 的__init__()方法

子类调用多个父类的__init__()方法

通过父类的类名调用__init__(self)方法

注意要传入self

class SmartPhone(Phone,IntelligentDevice):
    def __init__(self):
        Phone.__init__(self,"A11","2G","64G")
        IntelligentDevice.__init__(self)

注意:

这种在子类中直接写父类类名的方法,要注意,一旦父类改名了,子类中的父类类名也要及时修改

多继承的问题

见下面UML类图:

  1. B类继承A类,C类继承A类和B类,这种继承方式 不合理
  2. C类的__init__()方法可能会调用A类的__init__()方法,并且也可能调用B类的__init__()方法,B类的__init__()方法可能调用A类的__init__()方法,那么A类的__init__()方法会被执行多次

总结

  1. 子类可以 继承 多个父类,也就继承了 所有父类 的 方法,和第一个父类的 属性

  2. 多继承中的__init__()方法

    1. 如果子类没有实现__init__()方法,会执行第一个父类的__init__()方法。
      所以会 继承第一个父类 的实例属性

    2. 如果子类实现了__init__()方法,就执行自己的__init__()方法。
      要继承父类的实例属性,就要执行super().__init__()方法,调用 第一个父类 的__init__()方法

    3. 要继承 所有父类的属性,就要通过 父类名 调用 所有父类的__init__()


原文出处:/show_1EF2GKFx8RIg.html