day21--继承--派生

继承:

什么是继承?

​ 继承是一种新建类的方式,新建的类称之为字类或派生类,继承的父类称之为基类或超类。

​ 在python中,一个子类可以继承多个父类。

​ 在其他语言中,一个子类只能继承一个父类。

继承的作用:

​ 解决代码的冗余。

如何实现继承?

​ 1.先确认谁是子类,谁是父类。

​ 2.在定义类子类时,子类名(父类名)。

# 父类
class Father1:
    x = 1
    pass

class Father2:
    pass

#子类
class Sub(Father1, Father2):
    pass
#子类.__bases__查看父类
print(Sub.__bases__)
print(Sub.x)

如何寻找继承关系:

​ 1.确认谁是子类

​ 2.确认谁是父类

​ -- 抽取对象之间相似的部分总结出类。

​ --抽取类之间相似的部分,总结出父类。

#代码冗余:
#老师类
class OldboyTeacher:
    school = 'oldboy'
    country = 'China'

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

    def change_score(self):
        print(f'老师{self.name}正在修改分数...')

#学生类
class OldboyStudent:
    school = 'oldboy'
    country = 'China'

    def __init__(self, name, age, sex):
        self.name = name
        self.age = age
        self.sex = sex
        #学生选课程
    def choose_course(self):
        print(f'学生{self.name}正在选择课程...')

#学生类
stu1 = OldboyStudent('AA', 19, 'female')
print(stu1.school, stu1.name, stu1.age, stu1.sex) #oldboy AA 19 female

#老师
tea1 = OldboyTeacher('tank', 18, 'male')
print(tea1.school, tea1.name, tea1.age, tea1.sex) # oldboy tank 18 male

# 解决代码冗余问题
#老男孩人类
class OldboyPeople:  #我们经过分析可以得到上面学生类和老师类共同拥有						的特征,我们定义老男孩人类的父类。
    school = 'oldboy'
    country = 'China'

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

#老师类:
class OldboyTeacher(OldboyPeople):  #我们下面可以直接继承父类
    # 老师修改分数
    def change_score(self):
        print(f'老师{self.name}正在修改分数...')

# 学生类
class OldboyStudent(OldboyPeople):   # #我们下面可以直接继承父类
    #学生选课程
    def choose_course(self):
        print(f'学生{self.name}在选择课程...')

stu1 = OldboyStudent('AA', 39, 'female')
print(stu1.school, stu1.name, stu1.age, stu1.sex)#oldboy AA 39 female
tea1 = OldboyTeacher('大脸', 75, 'female')
print(tea1.school, tea1.name, tea1.age, tea1.sex)#oldboy 大脸 75 female

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

注意: 程序的执行顺序是由上到下,父类必须定义在子类的上方。

​ -- 在继承背景下,对象属性的查找顺序:

​ 1.先从对象自己的名称空间中查找

​ 2.对象中没有,从子类的名称空间中查找。

​ 3.子类中没有, 从父类的名称空间中查找,若父类没有,则会报错!

派生

​ 指的是子类继承父类的属性与方法,并且派生出自己独有的属性与方法。

​ 若子类中的方法与父类的相同,优先用子类的。

#父类:
class Foo:
    def f1(self):
        print('from Foo.f1...')

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

#子类
class Bar(Foo):
    def f1(self):
        print('from Bar.f1...')
    def func(self):
        print('from Bar.func...')

# bar_obj = Bar()
# bar_obj.f1() # from Bar.f1...
# bar_obj.func()  # from Bar.func...
# bar_obj.f2()  # from Foo.f2...

bar_obj = Bar()
bar_obj.f2() #from Foo.f2...
                #from Bar.f1...  #因为子类和父类中的方法名一样,优先使用子类名,

子类继承父类并重用父类的属性与方法

子类继承父类,派生出自己的属性与方法,并且重用父类的属性与方法。

问题: 子类重写父类的_ _ init _ _ 导致代码更加冗余

解决问题:子类重用父类的属性,并派生出新的属性
--两种方式:
--1.直接引用父类的_ _ init _ _为其传参,并添加子类的属性。
--2.通过super来指向父类的属性。
--super()是一个特殊的类,调用super得到一个对象,该对象指向父类的名称空间。

注意: 使用哪一种都可以,但不能两种方式混合使用。

#解决方法
#方式一
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, sal):
        # self.name = name
        # self.age = age
        # self.sex = sex
        # #类调用类内部的__init__,值时一个普通函数
        OldboyPeople.__init__(self, name, age, sex)
        self.sal = sal

    def change_score(self):
        print(f'老师{self.name}修改分数...')

class OldboyStudent(OldboyPeople):

    def __init__(self, name, age, sex, girl):
        OldboyPeople.__init__(self, name, age, sex)
        self.girl = girl
    def choose_course(self):
        print(f'学生{self.name}选择课程...')

tea1 = OldboyTeacher('tank', 17, 'male', 15000000)
print(tea1.name, tea1.age, tea1.sex, tea1.sal)

stu1 = OldboyStudent('姚玉鑫', 28, 'male', '凤姐')
print(stu1.name, stu1.age, stu1.sex, stu1.girl)

#方法二
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, sal):
        super().__init__(name, age, sex)
        self.sal = sal

    def change_score(self):
        print(f'老师{self.name}修改分数...')

class OldboyStudent(OldboyPeople):
    def __init__(self, name, age, sex, girl):
        super().__init__(name, age, sex)
        self.girl = girl

    def choose_course(self):
        print(f'学生{self.name}选择课程...')

tea1 = OldboyTeacher('tank', 17, 'male', 15000000)
print(tea1.name, tea1.age, tea1.sex, tea1.sal)


stu1 = OldboyStudent('姚玉鑫', 28, 'male', '凤姐')
print(stu1.name, stu1.age, stu1.sex, stu1.girl)
经典类与新式类(了解)
  • 新式类:

    ​ --1.凡是继承object的类或子孙类都是新式类。

    ​ --2.在python3中所有的类都默认继承object。

  • 经典类:

    --1.在python2中才会有经典类与新式类之分。

    --2.在python2中,凡是没有继承object的类,都是经典类。

supre严格遵循mro继承顺序

调用mro返回的是一个继承序列: (了解知识点)

​ super的继承顺序严格遵循mro继承序列。

在python3中提供了一个查找新式类查找顺序的内置方法. mro(): 会把当前类的继承关系列出来。

class Father1:
    x = 10
    pass
class Father2:
    x = 20
    pass
#多继承的情路况下:从左到右
class Sub(Father1, Father2):
    def __init__(self):
        print(super().__delattr__)

print(Sub.mro())
obj = Sub()
print(object)

多继承情况下造成 “钻石继承”

​ mro的查找顺序:

​ 新式类:

​ 广度优先

​ 经典类:

​ 深度优先

# 了解:
# 新式类:
class A(object):
    # def test(self):
    #     print('from A')
    pass

class B(A):
    # def test(self):
    #     print('from B')
    pass

class C(A):
    # def test(self):
    #     print('from C')
    pass
class D(B):
    # def test(self):
    #     print('from D')
    pass

class E(C):
    # def test(self):
    #     print('from E')
    pass

class F(D, E):
    # def test(self):
    #     print('from F')
    pass

# F-->D-->B-->E-->C-->A-->object
# print(F.mro())
obj = F()
obj.test()
posted @ 2019-11-26 20:41  猫-园  阅读(80)  评论(0编辑  收藏  举报