继承与派生

继承

什么是继承:

继承是一种创建新类的方式,新建的类可以继承一个或多个父类(python支持多继承), 父类又可以称之为基类或超类,新建的类称为派生类或子类.
子类会’遗传’父类的属性,从而解决代码重用问题
为什么要用继承
减少类与类之间的代码冗余的问题

  • python中类的继承分为: 单继承和多继承
class ParentClass1:   #定义父类
	pass

class ParentClass2:   #定义另一个父类
	pass

class SubClass1(ParentClass1):  # 单继承,基类是ParentClass1,派生类是SubClass1
	pass

class SubClass2(ParentClass1,ParentClass2): # python支持多继承,用逗号分隔开多个继承的类
	pass

继承与抽象(先抽象再继承)

如何使用继承
继承描述的是子类与父类之间的关系, 是一种什么是什么的关系. 要找出这种关系,必须先抽象再继承

  • 抽象:即抽取类似或者说比较像的部分.
    抽象分成两个层次:

    • 1.将梅西和奥巴马这两个对象比较像的部分抽取成类;
    • 2.将人,狗,猪这三类比较像的部分抽取称父类.
      抽象最主要的作用是划分类别(可以隔离关注点, 降低复杂度)
      在这里插入图片描述
  • 继承:是基于抽象的结果,通过编程语言去实现它, 肯定是先经历抽象这个过程,才能通过继承的方式去表达出抽象的结构.
    抽象只是分析和设计的过程中,一个技巧.通过抽象可以得到类
    在这里插入图片描述

  • python2与python3在继承上的区别
    新式类: 但凡继承object类的子类,以及该子类的子子类,…都称之为新式类
    经典类:没有继承object类的子类,以及子类的子子类,…都称之为经典类
    只有python2中才区分新式类与经典类,python3自动生成父类object,都是新式类,现在也都用新式类

继承的背景下属性查找的顺序

  • 在单继承的背景下:无论是新式类还是经典类属性查找顺序都一样
    • 先obj(对象)–>类–>父类…
class C:
    xxx='C'    # 如果对象obj和类A/类B都没有属性'xxx'会找到B的父类C的'xxx'
    pass

class B(C):
    xxx='B'    # 如果对象obj和类A都没有属性'xxx'会找到A的父类B的'xxx'
    pass

class A(B):
    xxx='A'    # 如果对象obj没有属性'xxx'会找到类A的'xxx'
    pass

obj=A()
obj.xxx=111
print(obj.xxx)   # obj--> A--> B--> C
  • 在多继承背景下:如果一个子类继承了多个分支,但是多个分支没有汇聚到一个非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)   # 查找顺序是obj-> A-> B-> E-> C-> F-> D->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)  #可以查看mro列表

这样会有一个疑问,为什么要按照这样的问题查找,其实这是python给我们内置的方法,class之后会根据算法得到一个mro列表,属性查找顺序是按照mro列表从左到右来查找的.你运行一下上面的print(A.mro)
在这里插入图片描述
我们上面说的广度优先\深度优先都是用来便于理解的

class A:
    def test(self):
        print('A.test')
        super().test()
class B:
    def test(self):
        print('from B')
class C(A,B):
    pass

c=C()
c.test()
print(C.mro())
'''
这个的运行结果是:
A.test
from B
[<class '__main__.C'>, <class '__main__.A'>, <class '__main__.B'>, <class 'object'>]
A没有继承B 还是访问到了B,因为他是根据C的mro列表的顺序来的
'''

派生

子类也可以添加自己新的属性或者在自己这里重新定义这些属性(不会影响到父类),根据上面的属性查找顺序,一旦重新定义了自己的属性且与父类重名,那么调用新增的属性时,就以自己为准了。

我们说继承的用途是减少类和类之间的代码冗余的问题,所以我们通过继承父类来实现访问父类属于功能的需求.

  • 在子类派生出的新功能中如何重用父类的功能:
  • 方式一: 知名道姓地访问某一个类中的函数,(这种方法是不是继承都可以调用)
# 我们用选课系统来举例
# 先抽象再继承 的方式,这里不写分析过程
# 因为两个类有相同的部分,所以定义一个共同的父类
class OldboyPeople:
	school = 'Oldboy'
	def __init__(self,name,age,gender):
		self.name = name
		self.age = age
		self.gender = gender

# 定义一个学生类,继承了OldboyPeople父类
class OldboyStudent(OldboyPeople):

    def choose_course(self):
        print('%s is choose course' %self.name)

# 定义一个教师类,继承了OldboyPeople父类
class OldboyTeacher(OldboyPeople):
	# 派生新的功能
    def __init__(self,name,age,gender,level,salary):
    	# 调用父类的功能,用指名道姓的方式, 类名.函数(参数)
        OldboyPeople.__init__(self,name,age,gender)
        # 派生的init功能
        self.level = level
        self.salary = salary

    def score(self,stu,num):
        stu.num = num
        print('老师%s给学生%s打分%s' %(self.name,stu.name,num))

stu = OldboyStudent('wood',18,'male')
tea = OldboyTeacher('egon',18,'male',10,30000)
# print(tea.__dict__)
tea.score(stu,90)
  • 方式二:super(OldboyTeacher,self),在python3中super可以不传参数,调用该函数会得到一个特殊的对象,该对象时专门用来访问父类中的属性.
    强调:super会严格按照属性的查找方式,也就是参照对象self所在类的mro列表依次查找属性
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 is choose course' %self.name)

class OldboyTeacher(OldboyPeople):

    def __init__(self,name,age,gender,level,salary):
    	# 用super函数重用父类的功能,python3可以不传参
        # super(OldboyPeople,self).__init__(name,age,gender)
        super().__init__(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))

stu = OldboyStudent('wood',18,'male')
tea = OldboyTeacher('egon',18,'male',10,30000)
# print(tea.__dict__)
tea.score(stu,90)
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值