继承

继承

一、什么是继承

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

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方法进行修改属性,就是去定义一个函数去修改,没有什么特别的
原文地址:https://www.cnblogs.com/yanjiayi098-001/p/11418851.html