zoukankan      html  css  js  c++  java
  • Python入门之面向对象之类继承与派生

    本章内容

        一、继承

        二、抽象类

        三、继承的实现原理

    =======================================================

    一、继承

      

      1. 继承的定义

        继承是一种新建类的方式,新建的类被称为子类,子类会继承父类的属性。

        在Python中支持,一个子类(派生类——可以继承一个或者多个父类(基类或者超类)

        

      2. 为什么要用继承

        继承可以有效减少代码冗余

      3. 如何使用继承

        继承代码示例

    # 继承示例
    class Father1:
            pass
    
    class Father2:
            pass
    
    class Son1(Father1):   # Son1继承Father1
        pass
    
    class Son2(Father1,Father2):   # Son2同时继承Father1 & Father2
        pass
    
    print(Son1.__bases__)
    print(Son2.__bases__)
    
    print(Father1.__bases__)
    print(Father2.__bases__)

        以上代码的结果如下:

    (<class '__main__.Father1'>,)                             #Son1继承Father1
    (<class '__main__.Father1'>, <class '__main__.Father2'>)  #Son2继承Father1,Father2
    (<class 'object'>,)        #Python3中有默认父类object
    (<class 'object'>,)        #Python3中有默认父类object
    # 在python3新建的类,默认都有一个父类(object) 
    
    # 在python2中,默认是没有父类,可以添加(object)为父类

        

        需要注意Python2和Python3中关于类的分类是不一样的:

    #Python2中的类:
    #   
    #   1.经典类
    #        指的是没有继承默认父类object的类,以及没有继承object类的子类
    #
    #   2.新式类
    #        值得是继承默认父类object以及object类子类的类
    #
    #
    #Python3中的类:
    #    
    #    统一都是新式类

      4. 建立继承关系

        继承是类与类之间的关系,需要寻找这种关系,先进行抽象,然后建立继承

        子类所共有的特征,由父类进行统一配置管理

    class SchoolPeople:
        
        school = 'SH high school'
    
        def __init__(self,name,age,gender):
            self.name = name
            self.age = age
            self.gender = gender
        
        def tell_info(self):
            print('School:Name is %s, Age is %s, Gender is %s' %(name,age,gender))
    
    class SchoolStudent(SchoolPeople): #继承SchoolPeople
    
        def learn(self):
            print('%s is learning' %name)
    
        def tell_info(self):
            print('I'm student %s, Age is %s, Gender is %s ' %(name,age,gender))
    
    class SchoolTeacher(schoolPeople):  #继承SchoolPeople
    
        def teach(self):
            print('%s is teaching' %name)
         
        def tell_info(self):
            print('I'm teacher %s, Age is %s, Gender is %s ' %(name,age,gender))
    
    student1 = SchoolStudent('Bob','22','Male')
    teacher1 = SchoolTeacher('Ajax','33','Female')
    
    print(student1.__dict__)
    print(student1.school)
    print(teacher1.__dict__)
    
    #子类已经自己定义tell_info()函数,显示格式将按照子类的格式显示,不需要按照父类的格式
    
    student1.tell_info()
    teacher1.tell_info()

        请仔细查看如下代码:

    class Foo:
        def F1(self):
            print('Foo.F1')
    
        def F2(self):
            print('Foo.F2')
            self.F1()
    
    class Bar(Foo):   #继承Foo
        def F1(self):   #子类中同时也有与父类同名的方法F1
            print('Bar.F1')
    
    obj = Bar()
    obj.F2()      
    # obj先到父类Foo中找到F2方法运行
    # 运行到self.F1()的时候会调用子类Bar自己的F1()方法,而不在调用父类的F1()方法

        以上显示的结果为:

    Foo.F2
    Bar.F1

      

      5. 子类派生出新的方法中重用父类的功能

       派生,是指子类定义自己新的属性,如果与父类同名,以子类自己的为准

        a. 调用父类方法,指名道姓的使用,请看如下代码

    class SchoolPeople:
        school = 'oldboy'
    
        def __init__(self, name, age, sex):
            self.name = name
            self.age = age
            self.sex = sex
    
        def tell_info(self):
            print("""
            ===========个人信息==========
            姓名:%s
            年龄:%s
            性别:%s
            """ %(self.name,self.age,self.sex))
    
    
    class SchoolTeacher(SchoolPeople):    # 继承SchoolPeople
        
        def __init__(self, name, age, sex, level, salary):
            # self.name = name
            # self.age = age
            # self.sex = sex
            SchoolPeople.__init__(self,name, age, sex)   # 点名指向SchoolPeople
    
            self.level = level
            self.salary = salary
    
        def tell_info(self):
        SchoolPeople.tell_info(self)     # 点名指向SchoolPeople
            print("""
            等级:%s
            薪资:%s
            """ %(self.level,self.salary))
    
    tea1 = SchoolTeacher('Bob', 18, 'male', 9, 50k)
    # print(tea1.name, tea1.age, tea1.sex, tea1.level, tea1.salary)
    
    
    tea1.tell_info()

        b. 调用父类方法,使用super()方法

          注意区分Python2和Python3中的super()的格式

          这种方法只能调用父类的方法

    class SchoolPeople:
        school = 'oldboy'
    
        def __init__(self, name, age, sex):
            self.name = name
            self.age = age
            self.sex = sex
    
        def tell_info(self):
            print("""
            ===========个人信息==========
            姓名:%s
            年龄:%s
            性别:%s
            """ %(self.name,self.age,self.sex))
    
    
    class SchoolTeacher(SchoolPeople):    # 继承SchoolPeople
        
        def __init__(self, name, age, sex, level, salary):
            # self.name = name
            # self.age = age
            # self.sex = sex
            super().__init__(self,name, age, sex)   # 使用super()指向父类,Python3的格式
            #super(SchoolPeople,self).__init__(self,name, age, sex)     Python2的格式
            self.level = level
            self.salary = salary
    
        def tell_info(self):
            super().tell_info(self)      # 使用super()指向父类,Python3的格式
            #super(SchoolPeople,self).tell_info(self)    Python2的格式
            print("""
            等级:%s
            薪资:%s
            """ %(self.level,self.salary))
    
    tea1 = SchoolTeacher('Bob', 18, 'male', 9, 50k)
    # print(tea1.name, tea1.age, tea1.sex, tea1.level, tea1.salary)
    
    
    tea1.tell_info()

    二、抽象类

      

      主要使用abc模块,实现归一化,父类有的方法,子类必须有。

      需要在父类的方法头部加上@abc.abstractclassmethod

    class File(metaclass=abc.ABCMeta):
        @abc.abstractmethod 
        def read(self):   #必须要定义下面的方法,如果没有就不让实例化
            pass
        @abc.abstractmethod
        def write(self):
            pass
    class Sata(File):
        def read(self):
            pass
        def write(self):
            pass
        def asb(self):
            print('adsf')
    Fil=Sata()
    Fil.asb()
    print(Sata.mro())

    三、继承的实现原理

      1、继承顺序:

        经典类:当类是经典类时,多继承情况下,在要查找属性不存在时,会按照深度优先的方式查找下去

        新式类:当类是新式类时,多继承情况下,在要查询属性不存在时,会按照广度优先的方式查找下去

      

      2、方法解析顺序(Method Resolution Order, MRO)

      

        在多重继承中存在不相关的祖先类实现同名方法引起的冲突问题,这种问题称作“菱形问题”。

        Python依靠特定的顺序遍历继承图,这个顺序叫做方法解析顺序。

        如图,左图是类的UML图,右图中的虚线箭头是方法解析顺序:

     

      3、使用属性来查看继承的顺序:

        print(类名.mro())

    class A(object):
        # def test(self):
        #     print('from A')
        pass
     
    class B(A):
        # def test(self):
        #     print('from B')
        pass
     
    class C(A):
        # def test(self):
        #     print('from C')
        pass
    class D(B):
        # def test(self):
        #     print('from D')
        pass
     
    class E(C):
        # def test(self):
        #     print('from E')
        pass
    class F(D,E):
        # def test(self):
        #     print('from F')
        pass
     
    f1=F()
    print(F.mro())

      4. 处理多重继承的建议

     

      (1)把接口继承和实现继承区分开;

      •   继承接口:创建子类型,是框架的支柱;

      •   继承实现:通过重用避免代码重复,通常可以换用组合和委托模式。

      (2)使用抽象基类显式表示接口;

      (3)通过混入重用代码;
        混入类为多个不相关的子类提供方法实现,便于重用,但不会实例化。并且具体类不能只继承混入类。

      (4)在名称中明确指明混入;
        Python中没有把类声明为混入的正规方式,Luciano推荐在名称中加入Mixin后缀。如Tkinter中的XView应变成XViewMixin。

      (5)抽象基类可以作为混入,反过来则不成立;
        抽象基类与混入的异同:

      •   抽象基类会定义类型,混入做不到;

      •   抽象基类可以作为其他类的唯一基类,混入做不到;

      •   抽象基类实现的具体方法只能与抽象基类及其超类中的方法协作,混入没有这个局限。

      (6)不要子类化多个具体类;
        具体类可以没有,或者至多一个具体超类。
        例如,Class Dish(China,Japan,Tofu)中,如果Tofu是具体类,那么China和Japan必须是抽象基类或混入。

      (7)为用户提供聚合类;
        聚合类是指一个类的结构主要继承自混入,自身没有添加结构或行为。Tkinter采纳了此条建议。

      (8)优先使用对象组合,而不是类继承。
        优先使用组合可以令设计更灵活。

      组合和委托可以代替混入,但不能取代接口继承去定义类型层次结构。

     

  • 相关阅读:
    RF操作execl
    fiddler 设置代理以后不能访问网络的解决办法
    Eclipse没有Web插件和JavaEE插件咋整
    mysql 分页查询的标准写法
    java读写操作
    java 链接mysql
    关于博客
    响应式排版中的基础知识
    前端性能优化最佳实践
    HTTP必知必会
  • 原文地址:https://www.cnblogs.com/JetpropelledSnake/p/8808085.html
Copyright © 2011-2022 走看看