面向对象三大特性之继承
一.继承
1.什么是继承
继承是一种关系,必须存在两个对象才可能产生这一种关系。在程序中继承指的是类与类之间的关系。新建的类可以继承1个或者多个父类,父类又被称为基类,超类,新建的类可以被称为子类或派生类。
2.为什么要使用继承
在程序中,通过继承可以直接使用父类已有的代码,可以减少类与类之间的代码冗余。
3.怎么使用继承
#单继承
class Father: #定义父类 a=10 class Son( 父类的名称 Father): #定义子类 pass son=Son() print(son.a) >>>: 10
#多继承
class Father1: #定义父类
a=10
class Father2: #定义父类 b=10
class Son( 父类的名称 Father1,Father2):#python支持多继承,用逗号分隔开多个继承的类
son=Son()
print(son.a)
print(son.b)
>>>:
10
10
4.查看继承
print(Son.__bases__) #使用__bases__可以查看Son类所继承的所有父类 >>>: (<class '__main__.Father1'>, <class '__main__.Father2'>)
二.继承与抽象(先抽象后继承)
继承是类与类之间的一种关系,抽象是指抽取多个类中相同的部分形成一个类。
抽象分成两个层次:
1.将奥巴马和梅西这俩对象比较像的部分抽取成类;
2.将人,猪,狗这三个类比较像的部分抽取成父类。
抽象最主要的作用是划分类别(可以隔离关注点,降低复杂度)
继承:是基于抽象的结果,通过编程语言去实现它,肯定是先经历抽象这个过程,才能通过继承的方式去表达出抽象的结构。
三.派生
1.什么是派生
派生指的是子类继承某个父类,但是这个子类拥有自己独特的属性或者技能,那么该子类就称之为派生类,也就是说子类中出现了新内容那么他就是一个派生类。
注意:派生类一定是子类,但是子类不一定是一个派生类。
#普通子类
class Person: def __init__(self,name,age,sex): self.name = name self.age = age self.sex = sex def sayHI(self): print("hello 我是%s 今年%s岁 性别:%s" % (self.name,self.age,self.sex)) class Test(Person): pass #此时Test不能被称为派生类,它只是一个子类,因为Test类没有任何独特的内容,它的内容与父类完全一致。
#派生类
class Student(Person):# class Test(Person):
# pass
def __init__(self,name,age,sex,number):
self.name = name
self.age = age
self.sex = sex
self.number = number
# 上课
def up_class(self):
print("%s 正在上课.....")
#此时Student类是一个派生类,因为它比父类Person多了一个方法和一个number属性
在上述派生类的代码中,我们发现我们重新写了一个初始化函数将参数自动传进去,那么不就又回到了没有继承之前的写法了吗,有没有什么方法能让子类可以继续使用父类的特征,然后在添加一个可以自动传参的特征呢?下面我们就来介绍一些这个方法。
四.子类访问父类的方法
1.指名道姓的访问父类的方法
class Person: def __init__(self,name,age,sex): self.name=name self.age=age self.sex=sex class Student(Person): def __init__(self,name,age,sex,number): Person.__init__(self,name,age,sex) self.number=number stu1=Student("egon",18,"man","007") print(stu1.name,stu1.age,stu1.sex,stu1.number) >>>: egon 18 man 007 #看上面的代码,在子类的初始化函数中,直接调用父类名.__init__(self,.....)的形式能直接调用定义在父类中的初始化函数,从而达到了可以访问父类属性的目的。
2.使用super()函数的方式访问父类
class Person: def __init__(self,name,age,sex): self.name=name self.age=age self.sex=sex class Student(Person): def __init__(self,name,age,sex,number): super().__init__(name,age,sex) #python2中的用法,但是python3也兼容这种形式 # super(Student, self).__init__(name,age,sex) self.number=number stu1=Student("egon",18,"man","007") print(stu1.name,stu1.age,stu1.sex,stu1.number) >>>: egon 18 man 007
补充知识:super()函数对类中的方法也有相同的作用
class Person: def __init__(self,name,age,sex): self.name=name self.age=age self.sex=sex def sayHi(self): print("BYE BYE") class Student(Person): def __init__(self,name,age,sex,number): super().__init__(name,age,sex) self.number=number def sayHi(self): super().sayHi() print("see you tomorrow") stu1=Student("egon",18,"man","007") stu1.sayHi() >>>: BYE BYE see you tomorrow #当我们需要在子类继承父类的方法中添加新东西中,可以使用super函数的方法添加
五.继承关系下的属性查找问题 (子类出现了与父类重复的名字 称之为覆盖)
由于一个子类可以继承多个父类,所以有可能会出现菱形继承的形式,所以继承关系下的属性查找也分为两类
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() 顺序为:F->D->B->E->C->A
2.继承多个父类的继承关系下菱形继承下的属性查找规则:深度优先+广度优先
class S: a = 100 class A(S): # a = 1 pass class B(S): # a = 2 pass class C(S): # a = 3 pass class D(A): # a = 4 pass class E(B): # a = 5 pass class F(C): # a = 6 pass class G(D,E,F): pass g1 = G() print(g1.a) print(G.mro()) """ s a,b,c d,e,f g """ g->d->a->e->b->f->c->s
六.经典类与新式类
1.只有在python2中才分新式类和经典类,python3中统一都是新式类 2.在python2中,没有显式的继承object类的类,以及该类的子类,都是经典类 3.在python2中,显式地声明继承object的类,以及该类的子类,都是新式类 3.在python3中,无论是否继承object,都默认继承object,即python3中所有类均为新式类