• OPP三大特性之继承


    一、继承基本知识

    1.什么是继承

    继承是一种关系,描述两个对象之间,什么是什么的关系

    在程序中,继承描述的是类与类之间的关系

    例如a继承了b,a就能直接使用b已将存在的方法和属性

    a称之为子类,b称之为父类,也称之为基类

     

    2.为什么要使用继承

    继承的一方可以直接使用被继承一方已经有的东西

    其目的可以减少代码冗余,提高重用性

     

    3.如何使用继承

    class Base:
        desc = "这是一个基类"
    
        def show_info(self):
            print(self.desc)
    
        def make_money(self):
            print("一天赚一个亿...")
    
    
    class SubClass(Base):  # 子类为SubClass,它的父类为Base
        pass
    
    
    obj = SubClass()
    #即使类中什么都没有也可以使用父类中已有的内容
    obj.make_money()  # 一天赚一个亿...
    print(obj.desc)  # 这是一个基类

    二、抽象

    1.定义:

    将多个子类中相同的部分,进行抽取,形成一个新的类,这个过程称之为抽象过程

    2.正确的使用继承

    先抽象在继承

    继承一个已经现存的类,扩展或是修改原始的功能

    抽取老师和学生中相同的部分形成person类
    
    class Person:
        def __init__(self, name, age, gender):
            self.name = name
            self.age = age
            self.gender = gender
    
        def say_hi(self):
            print("name:%s,gender:%s,age:%s" % (self.name,self.gender,self.age))
    
    
    class Teacher(Person):  # 子类Teacher从父类Person中进行取值
        def teaching(self):
            print("老师教学生,写代码....")
    
    
    t1 = Teacher("jack","male",20)
    t1.say_hi()  # name:jack,gender:20,age:male
    
    
    class  Student(Person):
        pass
    
    stu1 = Student("rose","female",18)
    stu1.say_hi()  # name:rose,gender:18,age:female

    三、属性的查找顺序

    一个类必然继承另一个类,被继承的类也有可能继承了其他类,相当于C继承B,B又继承A

    class A:
        text = "haha"
    
    class B(A):  # B的父类是A
        text = "heihei"
        pass
    
    b = B()  # B中有自己的属性
    # b.text = "xixi"  # 如果这个值注释掉,那么它就会找自己所在的类,那么值就会是heihei
    
    print(b.text)  # xixi

    查找顺序:

    对象本身的名称空间 - > 类的名称空间 -> 父类的名称空间 -> 父类的父类名称空间 ->...object类

    会沿着继承关系一直往后查找,直到找到为止,由于object是所有类的根类,所以如果找不着最后都会查找object类!

     

    四、派生

    当一个子类中出现了与父类中不同的内容时,这个子类就称之为派生类

    通常子类都会写一写新代码,不可能和父类完全一样,即通常都是派生类,

    所以派生类指的就是子类

    class OldboyPeople:
        school = 'oldboy'
    
        def __init__(self, name, age, sex):
            self.name = name
            self.age = age
            self.sex = sex
    
        def f1(self):
            print('爹的f1')
    
    class OldboyTeacher(OldboyPeople):
        def __init__(self,name,age,sex,level,salary):
            self.name=name
            self.age=age
            self.sex=sex
    
            self.level=level
            self.salary=salary
    
        def change_score(self):
            print('teacher %s is changing score' %self.name)
    
        def f1(self):
            print('儿子的f1')
    
    tea1 = OldboyTeacher('egon', 18, 'male',9,3.1)
    print(tea1.name,tea1.age,tea1.sex,tea1.level,tea1.salary)

    五、覆盖

    也称之为重写

    在子类中如果出现与父类相同的属性名称时,根据查找顺序,

    优先使用子类中的属性

    class Person:
        def say_hi(self):
            print("hello")
    
    
    
    class Student(Person):
        def say_hi(self):
            print("hello world!")
    
    
    stu = Student()
    stu.say_hi()  # hello world!

    练习

    需求 实现一个能够限制元素类型的列表类

    **class MyList(list):**
        **def init(self,element_type):**
            **super().init() # 调用父类的初始化方法 来完成基本的初始化**
            **self.element_type = element_type**
    
    ```
    def append(self, object):
        """
        :param object: 是要存储的元素
        :return: 没有
        """
        if type(object) == self.element_type:
            #我们需要在这里访问父类的append函数来完成真正的存储操作
            super(MyList,self).append(object)
        else:
            print("sorry sir, you element type not is %s" % self.element_type)
    ```
    
    创建是指定要存储的元素类型
    
    m = MyList(int)
    
    当你有需求,是需要在创建对象时 干点什么事儿  那就该想到初始化方法
    
    m.append(1)
    print(m[0])
    m.append("121212")
    View Code

    六、子类访问父类中的内容

    方式一:指名道姓地调用(其实与继承没有什么关系的)

    直接调用父类当中的属性,减少代码冗余

    class OldboyPeople:
        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 OldboyTeacher(OldboyPeople):
    
        def __init__(self, name, age, sex, level, salary):
    
            OldboyPeople.__init__(self,name, age, sex)
    
            self.level = level
            self.salary = salary
    
        def tell_info(self):
            OldboyPeople.tell_info(self)
            print("""
            等级:%s
            薪资:%s
            """ %(self.level,self.salary))
    
    tea1 = OldboyTeacher('egon', 18, 'male', 9, 3.1)
    
    
    tea1.tell_info()

    方式二:super()调用(严格依赖于继承)

    uper()的返回值是一个特殊的对象,该对象专门用来调用父类中的属性

    了解:在python2中,需要super(自己的类名,self)

    class OldboyPeople:
        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 OldboyTeacher(OldboyPeople):
     
        def __init__(self, name, age, sex, level, salary):
            
            super(OldboyTeacher,self).__init__(name,age,sex)
    
            self.level = level
            self.salary = salary
    
        def tell_info(self):
          
            super().tell_info()
            print("""
            等级:%s
            薪资:%s
            """ %(self.level,self.salary))
    
    tea1 = OldboyTeacher('egon', 18, 'male', 9, 3.1)
    
    tea1.tell_info()

    注意:

    当继承一个现有的类,并且覆盖了父类的init方法时,必须在初始化方法的第一行调用父类的初始化方法,并传入父类所需的参数

     

    七、组合

    定义:

    组合是一种关系,描述两个对象之间的互相有什么关系

    将一个对象作为另一个对象的属性

    组合目的

    能够重用现有的代码

    class Equip: #武器装备类
         def fire(self):
             print('release Fire skill')
    
    class Riven: #英雄Riven的类,一个英雄需要有装备,因而需要组合Equip类
         camp='Noxus'
         def __init__(self,nickname):
             self.nickname=nickname
             self.equip=Equip() #用Equip类产生一个装备,赋值给实例的equip属性
    r1=Riven('锐雯雯')
    r1.equip.fire() #可以使用组合的类产生的对象所持有的方法

    组合与继承都是有效地利用已有类的资源的重要方式。但是二者的概念和使用场景皆不同

    1.继承的方式

    通过继承建立了派生类与基类之间的关系,它是一种'是'的关系,比如白马是马,人是动物。

    当类之间有很多相同的功能,提取这些共同的功能做成基类,用继承比较好,比如老师是人,学生是人

    2.组合的方式

    用组合的方式建立了类与组合的类之间的关系,它是一种‘有’的关系,比如教授有生日,教授教python和linux课程,教授有学生s1、s2、s3...

     

    八、新式类与经典类

    1.新式类:

    继承object的类,以及该类的子类,都是新式类

    在python3中,如果一个类没有指定继承object的父类,默认就继承 所以说python3中所有的类都是新式类

    2.经典类(只有在python2才区分经典类与新式类):

    没有继承object的类,以及该类的子类,都是经典类

     

    九、菱形继承

    在Java和C#中子类只能继承一个父类,而Python中子类可以同时继承多个父类,如A(B,C,D)

    如果继承关系为非菱形结构,则会按照先找B这一条分支,然后再找C这一条分支,最后找D这一条分支的顺序直到找到我们想要的属性

    如果继承关系为菱形结构,那么属性的查找方式有两种,分别是:深度优先和广度优先.

     

     

     

    这里谈到的广度优先不是简单的从左到右,像图中标识的依然会按照深度一层一层上找,

    但是如果下一个要找的类与继承列表中的其他类存在相同父类(就像EF有共同父类G),

    则不会查找公共父类,这一次深度查找结束,开始下一条查找路径(C -> F)

    当出现了菱形继承时,新式类,先深度,当遇到了共同父类时就广度

    新式类,就是深度优先

     

    经典类查找顺序

  • 相关阅读:
    消息中间件
    swagger2 接口文档,整个微服务接口文档
    Java并发编程笔记之基础总结(二)
    Java并发编程笔记之基础总结(一)
    Python3 web Crawler
    使用JetBrains Intellij IDEA 开发Java EE应用
    用 Tomcat 和 Eclipse 开发 Web 应用程序
    gvim背景配色
    COBOL学习(2)
    如何删除一个顽固的文件(win)
  • 原文地址:https://www.cnblogs.com/xiongying4/p/11247329.html
Copyright © 2020-2023  润新知