1 2 3 4

面向对象的继承和派生

继承

1.1什么是继承?

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

​ -在python中一个子类可以继承多个父类,(面试的时候可能会问)

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

1.2继承的作用?

​ -减少代码的冗余

1.3如何实现继承?

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

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

#父类
class Father1:
    x = 1
    pass
class Father2:
    pass

#子类
class Sub(Father1,Father2):
    pass
#子类查看父类 __bases__
print(Sub.__bases__)
print(Sub.x)
>>>>>>>>>>>>>>>>>
(<class '__main__.Father1'>, <class '__main__.Father2'>)
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:
    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('huyu',28,'male')
print(stu1.school,stu1.name,stu1.age,stu1.sex)

tea1 = OldboyTeacher('tank',17,'male')
print(tea1.school,tea1.name,tea1.age,tea1.sex)
>>>>>>>>>>>
oldboy huyu 28 male
oldboy tank 17 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('yuyu',20,'female')
print(stu1.school,stu1.name,stu1.age,stu1.sex)

tea1 = OldboyTeacher('tank',25,'male')
print(tea1.school,tea1.name,tea1.age,tea1.sex)
>>>>>>>>>>>>>>>>>>>>>
oldboy yuyu 20 female
oldboy tank 25 male
     

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

注意:

​ -程序的执行顺序是由上到下,父类必须定义在子类的上方

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

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

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

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

#父类
class Goo:
    x = 10
    pass

#子类
class Foo(Goo):
    # x = 100
    pass
foo_obj = Foo()
foo_obj.x = 20
print(foo_obj.x)
print(foo_obj.__dict__)
print(Foo.__dict__)
print(Goo.__dict__)
>>>>>>>>>>>>>>>>>>>
20  #####如果对象有,则先用对象里面分  如果里面没有,则是用子类的,如果子类里面没有的 则用父类的
{'x': 20}####这个因为对象名称空间中有
{'__module__': '__main__', '__doc__': None}####子类的
{'__module__': '__main__', 'x': 10, '__dict__': <attribute '__dict__' of 'Goo' objects>, '__weakref__': <attribute '__weakref__' of 'Goo' objects>, '__doc__': None}#####这个是父类的

4.派生

定义:指的是子类继承父类的属性和方法,并且派生出自己独有的属性和方法。

若子类中大方法与父类相同,优先用子类

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

#子类
class Bar(Foo):
    def f1(self):
        print('from Bar.f1...')
    def func(self):
        print('from Bar.func...')
bar_obj = Bar()
bar_obj.f1()
bar_obj.f2()
bar_obj.func()
>>>>>>>>>>>>>>>
from Bar.f1...
from Foo.f2...
from Bar.func...
#父类
class Foo():
    def f1(self):
        print('from Foo.f1...')
    def f2(self):#################正常的先调用父类的f2,这个里面的self相当于  									 bar_f1传入的是它的本身
        print('from Foo.f2...')
        
        self.f1()### 相当于bar_obj.f1() 调用的是自身的f1
#子类
class Bar(Foo):
    def f1(self):
        print('from Bar.f1...')
    def func(self):
        print('from Bar.func...')
bar_obj = Bar()
bar_obj.f2()
>>>>>>>>>>>>>>
from Foo.f2...
from Bar.f1...

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

#w问题:子类重写父类的__init__导致的代码的更加冗余
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
        self.sal = sal
    def change_score(self):
        print(f'老师{self.name}修改分数...')

class OldboyStudent(OldboyPeople):

    def __init__(self,name,age,sex,girl):
        self.name = name
        self.age = age
        self.sex = sex
        self.girl = girl
    def choose_course(self):
        print(f'老师{self.name}修改分数...')


tea1 = OldboyTeacher('tank',17,'male',150000)
stu1 = OldboyStudent('yaoyuxi',28,'male','美女')
print(tea1.name,tea1.age,tea1.sex,tea1.sal)
print(stu1.name,stu1.age,stu1.sex,stu1.girl)
###以上方法做的代码比较冗余 我们可以用更加简便的方法来操作

解决上述的问题 ;

​ -我们可以用子类重用父亲的属性,并派生出新的属性

两种方式:

​ 1.直接引用父类的——init--为其传参,并添加子类的属性;

​ 2.通过super来指向父类的属性super().init

​ -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):##把参数要传入
        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',150000)
print(tea1.name,tea1.age,tea1.sex,tea1.sal)
stu1 = OldboyStudent('yaoyuxi',28, 'female','美女')
print(stu1.name,stu1.age,stu1.sex,stu1.girl)
>>>>>>>>>>>>>>>>>>>
tank 17 male 150000
yaoyuxi 28 female 美女

#第二种方法
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)####特殊的对象,指向的是父类的名称空间
        								会将调用类传入的对象当作第一个参数传给———											init————()
        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',150000)
print(tea1.name,tea1.age,tea1.sex,tea1.sal)
stu1 = OldboyStudent('yaoyuxi',28, 'female','美女')
print(stu1.name,stu1.age,stu1.sex,stu1.girl)
>>>>>>>>>>>>>>>>>>>>>>>>
tank 17 male 150000
yaoyuxi 28 female 美女

经典式和新式类

了解类的

工作上遇不到 ,但是面试上会问的

​ -1.新式类

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

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

​ -2.经典类

​ 1.在python2中的才会有经典类和新式类之分

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

class User(object):####这个就是新式类的
    pass
class Sub(User):
    pass
print(User.__dict__)

7.super严格遵循mro的继承顺序

了解的知识点

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

多继承的情况下:从左向右

class Father1:
    x = 20
    pass
class Father2:
    x = 40
    pass
class Sub(Father1,Father2):
    pass
obj  = Sub()
print(Sub.mro())

print(object)
>>>>>>>>>>>>>>
[<class '__main__.Sub'>, <class '__main__.Father1'>, <class '__main__.Father2'>, <class 'object'>]  #####这个顺序就是Father1-->Father2从左												向右的查找
<class 'object'>
# 注意: super()会严格按照mro列表的顺序往后查找
# class A:
#     def test(self):
#         print('from A.test')
#         super().test()
#
#
# class B:
#     def test(self):
#         print('from B.test')
#
#
# class C(A, B):
#     pass
#
#
# c = C()
# # 检查super的继承顺序
# print(C.mro())
#
# # 去A找,有的话打印,然后super又执行了test,根据mro中查找打印B类中test。
# c.test()
# '''
# from A.test
# from B.test
# '''

8.mro

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

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####这个就是新式类的 查找的顺序 最后才找到顶层的A
# print(F.mro())
obj = F()
obj.test()
>>>>>>>>>>>>>
from F  ####先从F里面来找


这个新式类的属性查找:广度优先

这个是经典类的属性查找:深度优先

posted @ 2019-11-27 14:30  ^更上一层楼$  阅读(104)  评论(0编辑  收藏  举报