python学习第25天面向对象的三大特征之继承
一、什么是继承
在程序中继承是一种新建子类的方式,新创建的类称之为子类\派生类,被继承的类称之为父类\基类\超类。
继承描述的是一种遗传关系,子类可以重用父类的属性
二、为何用继承
减少类与类之间代码冗余的问题
三,如何用继承
先抽象再继承
1、python中类的继承分为:单继承和多继承
class ParentClass1: #定义父类 pass class ParentClass2: #定义父类 pass class SubClass1(ParentClass1): #单继承,基类是ParentClass1,派生类是SubClass pass class SubClass2(ParentClass1,ParentClass2): #python支持多继承,用逗号分隔开多个继承的类 pass
2、查看继承
>>> SubClass1.__bases__ #__base__只查看从左到右继承的第一个子类,__bases__则是查看所有继承的父类 (<class '__main__.ParentClass1'>,) >>> SubClass2.__bases__ (<class '__main__.ParentClass1'>, <class '__main__.ParentClass2'>)
3、经典类与新式类
1.只有在python2中才分新式类和经典类,python3中统一都是新式类 2.在python2中,没有显式的继承object类的类,以及该类的子类,都是经典类 3.在python2中,显式地声明继承object的类,以及该类的子类,都是新式类 3.在python3中,无论是否继承object,都默认继承object,即python3中所有类均为新式类 #关于新式类与经典类的区别,我们稍后讨论
提示:如果没有指定基类,python的类会默认继承object类,object是所有python类的基类,它提供了一些常见方法(如__str__)的实现。
4、新式类与经典类在属性查找中的区别
(1)单继承:
在单继承背景下,无论是新式类还是经典类属性查找顺序都一样,都要遵循 对象——》子类——》父类
# class Foo: # def f1(self): # print('Foo.f1') # # def f2(self): # print('Foo.f2') # self.f1() #obj.f1() # # class Bar(Foo): # def f1(self): # print('Bar.f1') # # obj=Bar() # obj.f2()
(2)多继承:
在多继承背景下,如果一个子类继承了多个分支,但是多个分支没有汇聚到一个非object类(非菱形继承),无论是新式类还是经典类属性查找顺序都一样:
会按照从左到右的顺序一个分支一个分支的查找下去
class E: # xxx='E' pass class F: # xxx='F' pass class B(E): # xxx='B' pass class C(F): # xxx='C' pass class D: # xxx='D' pass class A(B,C,D): # xxx='A' pass obj=A() # obj.xxx=111 # print(obj.xxx) print(A.mro())
[<class '__main__.A'>, <class '__main__.B'>, <class '__main__.E'>, <class '__main__.C'>, <class '__main__.F'>, <class '__main__.D'>, <class 'object'>]
在多继承背景下,如果一个子类继承了多个分支,但是多个分支最终汇聚到一个非object类(菱形继承问题)
# 新式类:广度优先查找:obj->A->B->E->C->F->D->G->object
# 经典类:深度优先查找:obj->A->B->E->G->C->F->D
class G: # xxx='G' # # class E(G): # xxx='E' # pass # # class F(G): # xxx='F' # pass # # class B(E): # xxx='B' # pass # # class C(F): # xxx='C' # pass # # class D(G): # xxx='D' # pass # # class A(B,C,D): # xxx='A' # pass # # # print(A.mro())
[<class '__main__.A'>, <class '__main__.B'>, <class '__main__.E'>, <class '__main__.C'>, <class '__main__.F'>, <class '__main__.D'>, <class '__main__.G'>, <class 'object'>]
PS:obj.mro能查看obj的属性查找顺序
5、在子类派生出的新功能中如何重用父类的功能:
(1)指名道姓地访问某一个类中的函数,与继承无关
class OldboyPeople: school = 'Oldboy' def __init__(self, name, age, gender): self.name = name self.age = age self.gender = gender
# class OldboyTeacher(OldboyPeople): # # tea, 'egon', 18, 'male', 10, 3000 # def __init__(self, name, age, gender,level,salary): # OldboyPeople.__init__(self, name, age, gender) # self.level=level # self.salary=salary ## tea=OldboyTeacher('egon',18,'male',10,3000) #__init___(tea,'egon',18,'male',10,3000) # print(tea.__dict__)
(2)super(OldboyTeacher,self),在python3中super可以不传参数,调用该函数会得到一个特殊的对象,该对象是专门用来访问父类中属性,
# 强调:super会严格参照类的mro列表依次查找属性
# class OldboyTeacher(OldboyPeople): # # tea, 'egon', 18, 'male', 10, 3000 # def __init__(self, name, age, gender,level,salary): # super().__init__(name, age, gender) # # self.level=level # self.salary=salary # # tea=OldboyTeacher('egon',18,'male',10,3000) #__init___(tea,'egon',18,'male',10,3000) # print(tea.__dict__)