继承
继承是一种新建类的方式,新建的类称为子类或者派生类,父类又可以称为基类或者超类
从字面意思来讲可以理解,子类可以来遗传父类的属性,我们在平时使用继承主要就是为了减少代码的冗余。在我们定义类的时候,类与类之间那些对象不同的属性就可能会有相同的重复代码。继承就是解决这种类与类之间的关系,寻找这种关系需要先抽象在继承
继承方式
class ParentClass1: #定义父类 pass class ParentClass2: #定义父类 pass class SubClass1(ParentClass1): #单继承,基类是ParentClass1,派生类是SubClass pass class SubClass2(ParentClass1,ParentClass2): #python支持多继承,用逗号分隔开多个继承的类 pass
查看继承
>>> SubClass1.__bases__ #__base__只查看从左到右继承的第一个子类,__bases__则是查看所有继承的父类 (<class '__main__.ParentClass1'>,) >>> SubClass2.__bases__ (<class '__main__.ParentClass1'>, <class '__main__.ParentClass2'>)
继承与抽象(先抽象再继承)
抽象最主要的作用是划分类别(可以隔离关注点,降低复杂度)
继承:是基于抽象的结果,通过编程语言去实现它,肯定是先经历抽象这个过程,才能通过继承的方式去表达出抽象的结构。
抽象只是分析和设计的过程中,一个动作或者说一种技巧,通过抽象可以得到类
属性查找
class Foo: def f1(self): print('Foo.f1') def f2(self): print('Foo.f2') self.f1() class Bar(Foo): def f1(self): print('Bar.f1') obj=Bar() obj.f2() # Foo.f2 # Bar.f1
派生
子类自己定义新的属性,如果与父类同名以子类为准
class Riven(Hero): camp='Noxus' def attack(self,enemy): #在自己这里定义新的attack,不再使用父类的attack,且不会影响父类 print('from riven') def fly(self): #在自己这里定义新的 print('%s is flying' %self.nickname)
在子类中派生出的新方法中重用父类的功能:
1、指名道姓的调用(与继承没有关系)


# class OldboyPeople: # def __init__(self,name,age,sex): # self.name=name # self.sex=sex # self.age=age # def tell_info(self): # print(''' # ============个人信息=========== # 姓名:%s # 年龄:%s # 性别:%s # '''%(self.name,self.age,self.sex)) # class Teacher(OldboyPeople): # def __init__(self,name,age,sex,salary,level): # OldboyPeople.__init__(self,name,age,sex) # self.salary=salary # self.level=level # def teach(self): # print('%s 讲课'%self.name) # def tell_info(self): # OldboyPeople.tell_info(self) # print(''' # 薪资:%s # 级别:%s # '''%(self.salary,self.level)) # # class Student(OldboyPeople): # def choice(self): # print('%s 选课'%self.name) # # tea1=Teacher('egon',18,'male',40,9) # stu1=Student('alex',38,'male') # # tea1.teach() # tea1.tell_info() # stu1.choice() # stu1.tell_info()
2、super()调用(严格依赖于继承)
super()的返回值是一个特殊的对象,该对象专门用来调用父类中的属性


# class OldboyPeople: # def __init__(self,name,age,sex): # self.name=name # self.sex=sex # self.age=age # def tell_info(self): # print(''' # ============个人信息=========== # 姓名:%s # 年龄:%s # 性别:%s # '''%(self.name,self.age,self.sex)) # class Teacher(OldboyPeople): # def __init__(self,name,age,sex,salary,level): # super().__init__(name,age,sex) # self.salary=salary # self.level=level # def teach(self): # print('%s 讲课'%self.name) # def tell_info(self): # super().tell_info() # print(''' # 薪资:%s # 级别:%s # '''%(self.salary,self.level)) # # class Student(OldboyPeople): # def choice(self): # print('%s 选课'%self.name) # # tea1=Teacher('egon',18,'male',40,9) # stu1=Student('alex',38,'male') # # tea1.teach() # tea1.tell_info() # stu1.choice() # stu1.tell_info()
了解知识:1、在python2当中super()的调用方式:super(自己的类名,self)
2、即使没有直接继承关系,super仍然会按照mro继续往后查找


#A没有继承B,但是A内super会基于C.mro()继续往后找 class A: def test(self): super().test() class B: def test(self): print('from B') class C(A,B): pass c=C() c.test() #打印结果:from B print(C.mro()) #[<class '__main__.C'>, <class '__main__.A'>, <class '__main__.B'>, <class 'object'>]
经典类和新式类
1.只有在python2中才分新式类和经典类,python3中统一都是新式类
2.在python2中,没有显式的继承object类的类,以及该类的子类,都是经典类
3.在python2中,显式地声明继承object的类,以及该类的子类,都是新式类
3.在python3中,无论是否继承object,都默认继承object,即python3中所有类均为新式类
继承实现原理
1、继承顺序


class A(object): def test(self): print('from A') class B(A): def test(self): print('from B') class C(A): def test(self): print('from C') class D(B): def test(self): print('from D') class E(C): def test(self): print('from E') class F(D,E): # def test(self): # print('from F') pass f1=F() f1.test() print(F.__mro__) #只有新式才有这个属性可以查看线性列表,经典类没有这个属性 #新式类继承顺序:F->D->B->E->C->A #经典类继承顺序:F->D->B->A->E->C #python3中统一都是新式类 #pyhon2中才分新式类与经典类 继承顺序
2、继承原理
对于你定义的每一个类,python会计算出一个方法解析顺序(MRO)列表,这个MRO列表就是一个简单的所有基类的线性顺序列表
>>> F.mro() #等同于F.__mro__ [<class '__main__.F'>, <class '__main__.D'>, <class '__main__.B'>, <class '__main__.E'>, <class '__main__.C'>, <class '__main__.A'>, <class 'object'>]
为了实现继承,python会在MRO列表上从左到右开始查找基类,直到找到第一个匹配这个属性的类为止。
而这个MRO列表的构造是通过一个C3线性化算法来实现的。我们不去深究这个算法的数学原理,它实际上就是合并所有父类的MRO列表并遵循如下三条准则:
1.子类会先于父类被检查
2.多个父类会根据它们在列表中的顺序被检查
3.如果对下一个类存在两个合法的选择,选择第一个父类
当你使用super()函数时,Python会在MRO列表上继续搜索下一个类。只要每个重定义的方法统一使用super()并只调用它一次,那么控制流最终会遍历完整个MRO列表,每个方法也只会被调用一次(注意注意注意:使用super调用的所有属性,都是从MRO列表当前的位置往后找,千万不要通过看代码去找继承关系,一定要看MRO列表)