一 . 类的继承与派生 :
1. 什么是继承:
在程序中继承是一种新建子类的方式, 新创建的类称之为子类,或者派生类.
被继承的类称之为父类,
继承描述的是一种遗传关系, 子类可以重用父类的属性.
2. 为何要用继承 :
继承可以减少类与类之间代码冗余的问题.
3. 如何继承 :
先抽象,再继承
抽象 :抽取出比较像的部分.. 最主要的作用是划分类别 (可以隔离关注点, 降低复杂度.)
继承 :是基于抽象的结果,通过编程语言去实现它. 肯定是先经历抽象这个过程,才能通过继承的方式去表示
出抽象的结构
抽象只是分析和设计的过程中,一个动作或者说一个技巧. 可以通过抽象来得到类.
示例 :
# 在python中继承的特点 : 有单继承 和 多继承
class Parent1:
pass
class Parent2:
pass
class Sub1(Parent1):
pass
class Sub2(Parent1,Parent2):
pass
print(Sub1.__bases__) # 查看它的基础,基本
print(Sub2.__bases__)
python2 与 python3中,继承上的区别:
新式类 : 但凡继承object类的子类, 以及该子类的子子类...都称之为新式类.
经典类 : 没有继承object类的子类, 以及该子类的子子类...都称之为经典类.
只有在python2中才区分新式类与经典类. (在python中也写上object,这个程序也可以在python2中兼容)
4. 基于继承解决类与类代码冗余的问题 :
在子类派生出的新功能中,如何重用父类的功能:
方式一: 指名道姓的访问某一个类中的函数,与继承无关,
class OldboyPeople: # 存放两个类似的相同属性. (父类)
school = 'Oldboy'
def __init__(self,name,age,gender):
self.name = name
self.age = age
self.gender = gender
class OldboyStudent(OldboyPeople) # 学生的类
def choose_course(self):
print('%s 正在选课' %self.name)
class OldboyTeacher(OldboyPeople):
def __init__(self,name,age,gender,level.salary):
OldboyPeople.__init__(slef,name,age,gender) # 指名道姓的找到父类里相同的属性
self.level = level
self.salary = salary
def score(self,stu,num):
stu.num = num
print('老师%s给学生%s打分%s' %(self,name,stu.name,num))
5. 在单继承的背景下属性的查找:
在单继承背景下, 无论是新式类,还是经典类, 属性查找顺序都一样.
顺序: 先 obj ---> 类 ---> 父类 --->......
class Foo:
def f1(self):
print('Foo 1')
def f2(self):
print('Foo 2')
self.f1() #obj.f1()
class Bar(Foo):
def f1(self):
print('Bar f1') # 打印这个结果
obj = Bar()
obj.f2()
6. 在多继承背景下, 如果一个子类继承了多个分支,但是多个分支没有汇聚到一个非object类.
无论新式类和经典类查找顺序都一样 :
顺序: 会按照从左到右的顺序一个分支一个分支的查找下去
A -->B-->E-->C-->F--D 最后在找object
class F:
pass
class E:
pass
class B(E):
pass
class C(F):
pass
class D:
pass
class A(B,C,D):
pass
在多个继承背景下, 如果一个子类继承了多个分支,但是多个分支最终汇聚到一个非object类 (菱形继承问题)
新式类的查找方式 : 广度优先查找 obj-->A-->B-->E-->C-->F-->D-->G-->object
经典类的查找方式 : 深度优先查找 obj-->A-->B-->E-->G-->C-->F-->D
这个查找顺序都是基于C3算法得来的结果,
C3 算法在python3里有一个内置的方法,xx . mro() 在mro列表中存放着C3算法的结果, 它是在定义类的时候就
开始计算了.
不管是单继承还是多继承或者是菱形继承, 都是按照C3算法的mro里的结果列表的顺序来查找.
7. 用super方法来重用父类的功能.
super(OldboyTeacher). 在python3中super可以不传参数,调用该函数会得到一个特殊的对象,该对象是专门用来
访问父类中的属性.
强调 : super会严格参照当前类的mro列表依次查找属性.
# 在子类派生出的新功能中, 如何重用父类的功能:
方式2 :
class OldboyPeople:
school = 'oldboy'
def __init__(self,name,age,gender):
self.name = name
self.age = age
self.gender = gender
class OldboyTeacher(OldboyPeople):
def __init__(self,name,age,gender,level,salary):
super(OldboyTeacher,self).__init__(name,age,gender) #super本身不用传参数
self.level = level
self.salary = salary
注意 : 两种方式都可以用,但是最好不要两种方式混着用.
总结 : 一般在搭建框架的时候才用到多继承, 继承这个方式以后能不用就不用, 好处确实是能减少代码冗余,
但是它把子类和父类的耦合加大. 程序的可读性变差. 继承可以用,但是一般在单继承的场景下再用.