一、继承基本知识
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")
六、子类访问父类中的内容
方式一:指名道姓地调用(其实与继承没有什么关系的)
直接调用父类当中的属性,减少代码冗余
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()
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的类,以及该类的子类,都是新式类
2.经典类(只有在python2才区分经典类与新式类):
没有继承object的类,以及该类的子类,都是经典类
九、菱形继承
在Java和C#中子类只能继承一个父类,而Python中子类可以同时继承多个父类,如A(B,C,D)
如果继承关系为非菱形结构,则会按照先找B这一条分支,然后再找C这一条分支,最后找D这一条分支的顺序直到找到我们想要的属性
如果继承关系为菱形结构,那么属性的查找方式有两种,分别是:深度优先和广度优先.
这里谈到的广度优先不是简单的从左到右,像图中标识的依然会按照深度一层一层上找,
但是如果下一个要找的类与继承列表中的其他类存在相同父类(就像E
与 F
有共同父类G
),
则不会查找公共父类,这一次深度查找结束,开始下一条查找路径(C -> F
)
当出现了菱形继承时,新式类,先深度,当遇到了共同父类时就广度
新式类,就是深度优先
ç»å ¸ç±»æ¥æ¾é¡ºåº