七.面向对象之继承与派生

一.初认识继承

1.1什么是继承

继承一种新建类的的方式,在python中支持一个儿子继承多个爹。新建的类称为子类或者派生类,父类又可以称为基类或者超类, 子类会”遗传“父类的属性。

1.2为什么要用继承

为了减少代码的冗余

1.3怎么用继承

class ParentClass1:
    pass

class ParentClass2:
    pass

class Subclass1(ParentClass1):
    pass

class Subclass2(ParentClass1,ParentClass2):#可以继承多个父类
    pass

print(Subclass1.__bases__)
print(Subclass2.__bases__)  #查看自己的父类

继承相关代码
继承相关代码

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

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

抽象即抽取类似或者说比较像的部分。
抽象分成两个层次: 
1.将奥巴马和梅西这俩对象比较像的部分抽取成类; 
2.将人,猪,狗这三个类比较像的部分抽取成父类。
抽象最主要的作用是划分类别(可以隔离关注点,降低复杂度)

继承:是基于抽象的结果,通过编程语言去实现它,肯定是先经历抽象这个过程,才能通过继承的方式去表达出抽象的结构。

抽象只是分析和设计的过程中,一个动作或者说一种技巧,通过抽象可以得到类

三.继承关系与继承的属性查找

3.1寻找继承关系

class OldboyPeople:
    school='oldboy'

    def __init__(self,name,age,sex):
        self.name=name
        self.age=age
        self.sex=sex

    def f1(self):
        print('爹的f1')

class OldboyTeacher(OldboyPeople):
    def change_score(self):
        print('teacher %s is changing score'%self.name)

tea1=OldboyTeacher('egon',18,'male')#OldboyTeacher.__init__(...) 实例化
print(tea1.__dict__)
print(tea1.name)
print(tea1.school)
tea1.f1()

class Foo:
    def f1(self):
        print('Foo.f1')

    def f2(self):
        print('Foo.f1')
        self.f1()

class Bar(Foo):
    def f1(self):
        print('Bar.f1')

obj=Bar()
obj.f2()
寻找继承关系相关代码

3.2基于继承再看属性查找

class OldboyPeople:
    school = 'oldboy'

    def __init__(self, name, age, sex):
        self.name = name
        self.age = age
        self.sex = sex

    def f1(self):
        print('爹的f1')
class OldboyTeacher(OldboyPeople):
    def change_score(self):
        print('teacher %s is changing score' %self.name)

tea1 = OldboyTeacher('egon', 18, 'male')
# print(tea1.__dict__)
# print(tea1.name)
# print(tea1.school)
# print(tea1.change_score)
# print(tea1.f1)

class Foo:
    def f1(self):
        print('Foo.f1')

    def f2(self): #self=obj
        print('Foo.f2')
        self.f1() #obj.f1()

class Bar(Foo):
    def f1(self):
        print('Bar.f1')

obj=Bar()
# print(obj.__dict__)
obj.f2()

# 答案为所以先从自己开始找,再找父类
# Foo.f2
# Bar.f1
基于继承再看属性查找

总结:查找顺序,从自己的类这里找,再从父类找。

四.派生

4.1什么是派生?继承和派生的区别是什么?

派生:在子类定义自己新的属性,如果与父类同名,以子类自己的为准(这是一种覆盖的效果)。
继承可以遗传父类的属性,派生可以定制自己的属性。
# #派生:在子类定义自己新的属性,如果与父类同名,以子类自己的为准(这是一种覆盖的效果)
# class OldboyPeople:
#     school = 'oldboy'
#
#     def __init__(self, name, age, sex):
#         self.name = name
#         self.age = age
#         self.sex = sex
#
#     def f1(self):
#         print('爹的f1')
# class OldboyTeacher(OldboyPeople):
#     def change_score(self):
#         print('teacher %s is changing score' %self.name)
#
#     def f1(self):
#         print('儿子的f1') #得到的是儿子的f1
#
# tea1 = OldboyTeacher('egon', 18, 'male')
# tea1.f1()
#
#

class OldboyPeople:
    school = 'oldboy'

    def __init__(self, name, age, sex):
        self.name = name
        self.age = age
        self.sex = sex

    def f1(self):
        print('爹的f1')

class OldboyTeacher(OldboyPeople):
    def __init__(self,name,age,sex,level,salary):
        self.name=name
        self.age=age
        self.sex=sex

        self.level=level
        self.salary=salary

    def change_score(self):
        print('teacher %s is changing score' %self.name)

    def f1(self):
        print('儿子的f1')

tea1 = OldboyTeacher('egon', 18, 'male',9,3.1)
print(tea1.name,tea1.age,tea1.sex,tea1.level,tea1.salary)

#继承可以遗传父类的属性,派生可以定制自己的属性
派生的相关代码

4.2在子类派生出的新方法中重用父类的功能

在子类派生出的新方法中重用父类的功能
方式一:指名道姓地调用(其实与继承没有什么关系的)
OldboyPeople.__init__(self,name, age, sex)

class OldboyPeople:
    school = 'oldboy'

    def __init__(self, name, age, sex):
        self.name = name
        self.age = age
        self.sex = sex

    def tell_info(self):
        print("""
        ===========个人信息==========
        姓名:%s
        年龄:%s
        性别:%s
        """ %(self.name,self.age,self.sex))


class OldboyTeacher(OldboyPeople):
    #            tea1,'egon', 18, 'male', 9, 3.1
    def __init__(self, name, age, sex, level, salary):
        # self.name = name
        # self.age = age
        # self.sex = sex
        OldboyPeople.__init__(self,name, age, sex)

        self.level = level
        self.salary = salary

    def tell_info(self):
        OldboyPeople.tell_info(self)
        print("""
        等级:%s
        薪资:%s
        """ %(self.level,self.salary))

tea1 = OldboyTeacher('egon', 18, 'male', 9, 3.1)
# print(tea1.name, tea1.age, tea1.sex, tea1.level, tea1.salary)


tea1.tell_info()
方式一的相关代码
方式二:super()调用(严格依赖于继承)
super()的返回值是一个特殊的对象,该对象专门用来调用父类中的属性
了解:在python2中,需要super(自己的类名,self) 固定用法
class OldboyPeople:
    school = 'oldboy'

    def __init__(self, name, age, sex):
        self.name = name
        self.age = age
        self.sex = sex

    def tell_info(self):
        print("""
        ===========个人信息==========
        姓名:%s
        年龄:%s
        性别:%s
        """ %(self.name,self.age,self.sex))

class OldboyTeacher(OldboyPeople):
    #            tea1,'egon', 18, 'male', 9, 3.1
    def __init__(self, name, age, sex, level, salary):
        # OldboyPeople.__init__(self,name, age, sex)
        super(OldboyTeacher,self).__init__(name,age,sex)  #这是python2的方法

        self.level = level
        self.salary = salary

    def tell_info(self):
        # OldboyPeople.tell_info(self)
        super().tell_info()
        print("""
        等级:%s
        薪资:%s
        """ %(self.level,self.salary))

tea1 = OldboyTeacher('egon', 18, 'male', 9, 3.1)
# print(tea1.name, tea1.age, tea1.sex, tea1.level, tea1.salary)
tea1.tell_info()
方式二的相关代码

五.组合

5.1解决类与类之间代码冗余问题有两种解决方案

1、继承:描述的是类与类之间,什么是什么的关系
2、组合:描述的是类与类之间的关系,是一种什么有什么关系。一个类产生的对象,该对象拥有一个属性,这个属性的值是来自于另外一个类的对象
class Date:
    def __init__(self,year,mon,day):
        self.year = year
        self.mon = mon
        self.day = day

    def tell_birth(self):
        print('出生年月日<%s-%s-%s>' % (self.year, self.mon, self.day))

class OldboyPeople:
    school = 'oldboy'

    def __init__(self, name, age, sex):
        self.name = name
        self.age = age
        self.sex = sex

class OldboyTeacher(OldboyPeople):
    def __init__(self,name,age,sex,level,salary):
        super().__init__(name,age,sex)
        self.level=level
        self.salary=salary

    def change_score(self):
        print('teacher %s is changing score' %self.name)

class Oldboystudent(OldboyPeople):
    def __init__(self,name,age,sex,course,):
        super().__init__(name,age,sex,)
        self.course=course

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

tea1=OldboyTeacher('egon',18,'male',9,3.1)
date_obj=Date(2000,1,1)
date_obj.tell_birth()

tea1.birth=date_obj
# print(tea1.birth)
# tea1.birth.tell_birth()
# tea1.change_score()

stu1=Oldboystudent('张三',16,'male','linux')
stu1.birth=Date(2002,3,3)
stu1.birth.tell_birth()

 5.2组合练习

class OldboyPeople:
    school = 'oldboy'

    def __init__(self, name, age, sex,):
        self.name = name
        self.age = age
        self.sex = sex

class OldboyTeacher(OldboyPeople):
    def __init__(self,name,age,sex,level,salary):
        super().__init__(name,age,sex)
        self.level=level
        self.salary=salary

        self.courses=[]

    def change_score(self):
        print('teacher %s is changing score' %self.name)

    def tell_course_info(self):
        print(('老师%s 教授的课程信息如下' %self.name).center(50,'='))
        for course_obj in self.courses:
            course_obj.info()


class Oldboystudent(OldboyPeople):
    def __init__(self,name,age,sex):
        super().__init__(name,age,sex,)
        self.courses=[]

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

    def tell_course_info(self):
        print(('学生%s 学习的课程信息如下' % self.name).center(50, '='))
        for course_obj in self.courses:
            course_obj.info()

class Course:
    def __init__(self,cname,period,price):
        self.cname=cname
        self.period=period
        self.price=price

    def info(self):
        print('课程信息<名字:%s 周期:%s  价钱:%s>' %(self.cname,self.period,self.price))


tea1=OldboyTeacher('egon',18,'male',9,3.1)
stu1=Oldboystudent('张三',16,'male')

python=Course('Python全栈开发','5mons',3000)
linux=Course('Linux高级架构师','5mons',2000)
go=Course('Go开发工程师','3mons',1000)

六.经典类与新式类

在python2中有经典类与新式类之分
在python3中全都为新式类

'''
1、新式类:
    继承object的类,以及该类的子类,都是新式类

    在python3中,如果一个类没有指定继承的父类,默认就继承object
    所以说python3中所有的类都是新式类

2、经典类(只有在python2才区分经典类与新式类):
    没有继承object的类,以及该类的子类,都是经典类
'''
class Foo(object):
    pass

class Bar(Foo):
    pass

print(Foo.__bases__)
print(Bar.__bases__)
经典类与新式类相关代码

六.在多继承背景下的属性查找

pass

七.super()依赖继承

super()会严格按照mro列表从当前查找到的位置继续往后查找

class A:
    def test(self):
        print('A.test')
        super().f1()#调用父类的test方法
class B:
    def f1(self):
        print('from B')
class C(A,B):
    pass

c=C()
print(C.mro()) #C->A->B->object super是照这个列表来的   B是A的爹,A是C的爹

c.test()
super()依赖继承相关代码

 

posted @ 2018-12-28 20:54  王苗鲁  阅读(99)  评论(0编辑  收藏  举报