zoukankan      html  css  js  c++  java
  • 继承

    继承

    一、什么是继承

    ​ 继承是一种新建类的方式,继承了一个类,类中的属性和方法就在子类中了。

    1.1各种类介绍

    基类:在面向对象设计中,被定义为包含所有实体共性的class类型,被称为“基类”。经常用于封装。

    派生类:派生类必须通过使用派生类列表明确指出它是从哪个(哪些)基类继承而来的

    父类:被子类继承的类

    子类:继承父类的类

    1.2 如何使用继承

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

    1.3 新式类和经典类

    新式类:只要继承了object类,就是新式类,在python3中都是新式类。

    python3 中,默认继承object类

    class A:  #此处就默认他继承了object类
        pass
    

    ​ python2 中,需要显示指定的继承object类

    经典类:没有继承object类,就是经典类

    二、利用继承减少代码冗余

    2.1 多层继承

    class D:  #D继承object
        print('ddd')
    class C(D):  #c继承D
        print('ccc')
    class B(C):  #B继承c
        print('bbb')
    class A(B):    #A继承B
        print('aaa')
    

    2.2 多继承

    class D:  #D继承object
        print('ddd')
    class C:  
        print('ccc')
    class B:  
        print('bbb')
    class A(B,C,D):    #A继承B,C,D
        print('aaa')
    

    2.3 多继承的多层继承

    class G:  #G继承object
        print('ddd')
    class F(G):  
        print('ccc')
    class E(G):  
        print('bbb')
    class D(G):  
        print('ddd')
    class C(F):  
        print('ccc')
    class B(E):  
        print('bbb')
    class A(B,C,D):    #A继承B,C,D
        print('aaa')
    

    当我们写到上面的代码时,不料代码的继承写为了如下图继承的样子,我们称他为继承的菱形问题

    继承的菱形问题:新式类和经典类的查找顺序不一样

    img

    A-->B-->E-->G-->C-->F-->D

    img

    A-->B-->E-->C-->F-->D-->G

    --继承的菱形问题(显示的都继承一个类,不是object类):新式类和经典类的查找顺序是不一样的

    • 新式类(py3中全是新式类):广度优先---从左侧开始,一直往上找,找到菱形的顶点结束(不包括菱形顶点),继续下一个继承的父类往上找,找到菱形的顶点结束(不包括菱形顶点),最后找到菱形顶点
    • 经典类(只有py2中才有):深度优先---从左侧开始,一直往上找,找到菱形的顶点结束(包括菱形顶点)继续下一个继承的父类往上找,找到菱形的顶点结束(不包含菱形定点)

    --属性的查找顺序是什么?

    先找对象----》类中找-----》父类中找(多继承)-----》报错

    三、重用父类方法

    3.1 重用父类方法方式一

    指名道姓的用,跟继承没有关系

    • 指名道姓的方式在什么情况下用?

      1. 没有继承关系

      2. 如果继承了多个父类,super是按照mro列表找,现在想指名道姓的用某个父类的某个方法,就需要指名道姓的使用

    
    class Person: #父类  #默认继承object类
        school = 'oldboy'
        def __init__(self,name,age)
        self.name = name
        self.age = age
        def study(self):
            print('This is study method')
            
    class Student(Person):
        school = 'yyyyy'  #自己在里面面添加的属性
        def __init__(self,name,age,course):
            #如何重用父类的__init__方法
            person.__init__(self,name,age)  #重用Person,就会调用父类里面的所有东西
            self.course = course
        def study(self):
            Person.study(self)
            print(f"{self.name} is learning)
                
               
    Stu1 = Student('yjy',20,'python')
    stu1.school='xxx'
    print(stu1.school)
    stu1.study()
    -----------------------------------------------------------
    yyyy
    This is study method
    yjy is learning
            
    

    3.2 重用父类方法方式二

    通过super关键字,跟继承有关系

    • 有继承关系的时候,通常用super
    class Person: #父类   #默认继承object类
        school = 'oldboy'
        def __init__(self,name,age)
        self.name = name
        self.age = age
        def study(self):
            print('This is study method')
    class Student(Person):
        school = 'yyyyy'  #自己在里面面添加的属性
        def __init__(self,name,age,course):
            #如何重用父类的__init__方法
            #super() 会按照mro列表拿到父类对象,对象来调用绑定方法,不需要传递第一个参数
            #super()相当于得到了一个特殊对象,第一个参数不需要传,调用绑定方法,会把自己传过去
            super().__init__(name,age)  #经典类中写法:super(Student,self).__init__(name,age),为了兼容py2
            self.course = course
        def study(self):   #定义一个study方法
            Person.study(self)
            print(f"{self.name} is learning)
    --------------------------------------------------------------
    yyyy
    This is study method
    yjy is learning
    
    

    ps:A.mro,A.__mro__是继承查找顺序的列表(mro只在新式类中有mro)

    super很重要

    四、回顾绑定方法

    #定义一个学生类
    class Student:
        def __init__(self,name,age):
            self.name = name
            self.age = age
        #定义一个study方法
        def study(self):
            print(self.name)
            print('study.....')
        #定义一个改变名字的方法
        def change_name(self,new_name):
            print(f"原来的名字是{self.name}")
            self.name = new_name
            print(f"现在的名字是{self.name}")
    
    
    #方式一:类调用对象的绑定方法(写在类中的函数,没加装饰器),有几个参数就需要传几个参数
    Student.__init__(123,'yjy',20)   #会报错AttributeError: 'str' object has no attribute 'name'
    #方式二:类实例化对象,会自动调用__init__完成初始化操作,象的绑定方法的特殊之处,会把对象本身当做第一个参数传入
    stu = Student('yjy',18)
    print(stu.name)  #会输出yjy
    stu.study()  #会输出yjy  study.....
    
    #修改学生姓名的四种方式
    stu = Student('aaa',18)
    #方式一(直接进行修改属性)
    stu.name = 'bbb'
    print(stu.name)
    
    #方式二(对象调用change_name方法进行修改)
    stu.change_name('bbb')
    print(stu.name)
    
    #方式三(函数调用change_name方法进行修改)
    Student.change_name(stu,'bbb')
    print(stu.name)
    
    #方式四(定义一个普通的函数)
    def chang_name(obj,name):
        print(f"原来的名字是{obj.name}")
        obj.name = name
        print(f"现在的名字是{obj.name}")
    chang_name(stu,'bbb')
    print(stu.name)
    
    #其实函数调用change_name方法进行修改属性,就是去定义一个函数去修改,没有什么特别的
    
  • 相关阅读:
    Chapter 5. 集合---(ArrayList、Stack、queue、哈希表)
    Chapter 4. 数组
    第一章 代码无错就是优?——简单工厂模式
    条款34:区分接口继承和实现继承
    条款33:避免遮掩继承而来的名称
    条款32:确定你的public继承塑模出is-a关系
    条款12:复制对象时勿忘其每一部分
    A:魔兽世界之一:备战
    条款09:绝不在构造和析构过程中调用virtual函数
    7、数值算法
  • 原文地址:https://www.cnblogs.com/yanjiayi098-001/p/11418851.html
Copyright © 2011-2022 走看看