zoukankan      html  css  js  c++  java
  • (二十二)类与对象 ---- 继承

    什么时候用继承?

    1.当类之间有显著不同,且较小的类是较大的类的组件时,用组合比较好

    比如机器人类是一个大类,躯干类、胳膊类、腿类是小类

    2.当类之间有很多相同的属性与功能,提取这些共性作为基类,用继承比较好

    比如鸡和鸭,我们可以提取他们的共性(两只翅膀、用两只脚走路)做一个禽类,但是他们也有各自独特的个性(鸡会打鸣,鸭会游泳)

    class qing():                                 #共性提取为一个基类(禽类)
        wing = 2                                  #父类数据属性
        def __init__(self,owner):          
            self.owner = owner
        def walk(self):                           #父类函数属性
            print('%s用两只脚走路' %self.owner)
    
    class ji(qing):                               #鸡类继承禽类
        def da_ming(self):                        #子类有自己的函数属性
            print('%s会打鸣' %self.owner)
    
    class ya(qing):                               #鸭类继承禽类
        def you_yong(self):                       #子类有自己的函数属性
            print('%s会游泳' %self.owner)
    
    j1 = ji('小王家的鸡')                           #鸡类实例化
    j1.da_ming()                                  #可以调用实例自己的函数属性
    j1.walk()                                     #可以调用实例继承来的函数属性
    
    y1 = ya('小明家的鸭')                           #鸭类实例化
    y1.you_yong()                                 
    y1.walk()
    结果:

    小王家的鸡会打鸣
    小王家的鸡用两只脚走路
    小明家的鸭会游泳
    小明家的鸭用两只脚走路

    继承有两种含义

    含义一:子类继承基类的方法,并且做出自己的改变或扩展(代码重用),如上禽类的例子

    含义二:基类是一个接口类,子类继承这个接口类,并实现接口中定义的方法

    实践中,继承的第一种含义意义并不大,甚至是有害的,因为这种方式使得子类与基类出现强耦合

    继承的第二种含义就很重要了,它又叫“接口继承”

    接口继承实质上做了一个良好的抽象,这个抽象规定了一个兼容接口,使得外部调用者无需关心具体细节,可以一视同仁的处理实现了接口的所有对象——程序设计上,这叫归一化

    就像linux的泛文件概念(一切皆文件),所有东西都可以当文件处理,不必关心它是内存、磁盘还是网络(然后在内存、磁盘和网络的子类中,再去做针对性的底层设计,即具体实现接口类中定义的接口)

    如何强制子类必须实现基类中某些指定的方法和属性,否则就抛异常?python的abc模块就满足了这个需求。

    import abc
    class All_file(metaclass=abc.ABCMeta):          #abc.ABCMeta是一个用于实现抽象类的一个基础类
        @abc.abstractmethod                         #加上@abstractmethod之后,如果需要用到的这个方法则必须用新的方法将其实现
        def read(self):                             #子类必须实现读方法
            pass                                    #接口类不用实现逻辑,只是用来规范子类
        @abc.abstractmethod                         #子类必须实现写方法
        def write(self):
            pass
    
    class Disk(All_file):
        def read(self):
            print('disk read')
    
        def write(self):
            print('disk write')
    
    class Cdrom(All_file):
        def read(self):
            print('cdrom read')
    
        def write(self):
            print('cdrom write')
    
    class Mem(All_file):
        def read(self):
            print('mem read')
    
        def write(self):                     #如果这个write方法不写,将报错:TypeError: Can't instantiate abstract class Mem with abstract methods write
            print('mem write')
    
    m1=Mem()
    m1.read()                     #mem read
    m1.write()                    #mem write

    1.接口类的作用只是用来规范子类,所以他不用实现逻辑,写个pass就ok

    2.接口类不需要被实例化,也没有这个必要

    3.子类如果继承了接口类,就一定要实现接口类中加了@abstractmethod的方法

    继承的顺序

    python的类可以继承多个类,如果继承多个类,那么其继承顺序的方式有:深度优先和广度优先
    基类或者父类继承了object类,那么该类就是新式类,否则便是经典类
    注意:python3中统一都是新式类,pyhon2中才分新式类与经典类
    当类是经典类时,多继承情况下,会按照深度优先方法查找
    当类时新式类时,多继承情况下,会按照广度优先方法查找

    class A:
        def test(self):
            print('A')
        pass
    class B(A):
        def test(self):
            print('B')
        pass
    class C(A):
        def test(self):
            print('C')
        pass
    class D(B):
        def test(self):
            print('D')
        pass
    class E(C):
        def test(self):
            print('E')
        pass
    class F(D,E):
        def test(self):
            print('F')
        pass
    f1=F()                   #python3都是新式类,广度优先,所以继承顺序是:F--D--B--E--C--A
    f1.test()   
    
    print(F.__mro__)  #(<class '__main__.F'>, <class '__main__.D'>, <class '__main__.B'>, <class '__main__.E'>, <class '__main__.C'>, <class '__main__.A'>, <class 'object'>)

    B.C继承A,D继承B,E继承C,F继承D,E,我们看下F的继承顺序:

    如果是新式类,继承的顺序是:F--D--B--E--C--A,如图中绿线所示,左边的线不会找到头,这就是所谓的广度优先

    如果是经典类,继承的顺序是:F--D--B--A--E--C,如图中红线所示,左边的线直接找到头,这就是所谓的深度优先

    Python到底是如何实现继承的?

    对于定义的每一个类,Python会计算一个方法解析顺序列表(MRO列表),这个MRO列表就是一个简单的所有基类的线性顺序列表

    为了实现继承,Python会在MRO列表上从左到右开始查找基类,直到找到第一个匹配这个属性的类为止

    MRO列表遵循以下三条准则:

    • 子类会先于父类被检查;
    • 多个父类会根据它们在列表中的顺序被检查;
    • 如果对下一个类存在两个合法的选择,则选择第一个类;

    注意:只有新式类才有.__mro__这个属性,可以查看线性列表,经典类没有这个属性

     在子类中调用父类方法

    class People:
        def __init__(self,name,age):
            self.name = name
            self.age = age
    
        def run(self):
            print('%s 在跑!'%self.name)
    
    class China(People):
        def __init__(self,name,age,country):
            People.__init__(self,name,age)                  #子类中调用父类的__init__方法,可以用super().__init__(name,age) 代替,注意用super()调用父类的方法时不用传self
            self.country = country
        def run(self):
            People.run(self)                                #子类中调用父类的run方法  可以用super().run()代替
            print('%s人 %s 在跑!'%(self.country,self.name))
    
    p2 = China('Tom',26,'中国')
    p2.run()
  • 相关阅读:
    Spark Streaming企业运用
    spark企业运用
    sparkcore企业运用
    Spark GraphX从入门到实战
    sparkstreaming入门到实战
    sparkSql从入门到实战
    sparkcore入门到实战
    spark机器算法从入门到实战
    flink实时数仓从入门到实战
    github上克隆私有项目
  • 原文地址:https://www.cnblogs.com/xulan0922/p/10339245.html
Copyright © 2011-2022 走看看