面向对象之继承

今日学习总结:

一、继承介绍:

      注意:在python中,一个子类可以继承多个父类。在其他语言中,一个子类只能继承一个父类。

      1.什么是继承:

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

       2. 继承的作用:减少代码的冗余

        3.如何实现继承:

            先确认谁是子类,谁是父类(面试)

            在定义子类时:子类名(父类名)

         4.如何寻找继承关系:     

- 胡晨阳对象 ---> 人子类 ---> 动物父类
- 猪坚强对象 ---> 猪子类 ---> 动物父类
- 哈士奇对象 ---> 狗子类 ---> 动物父类

             01.确认谁是子类:

                  人、猪、狗都是子类

             02.确认谁是父类:

                 动物类是父类

             03.要先抽象,再继承

                   抽取对象之间相似的部分,总结出类

                   抽出类之间相似的部分,总结出父类

例子:

子类._ _bases_ _                #表示查看父类 

 

class Father1:
    x=1
    pass
class Father2:
    x=10
    pass
class Father3:
    x=100
    pass

#子类
class Boby(Father1,Father2,Father3):
    pass

print(Boby.x)                        #1
print(Boby.__bases__)                #(<class '__main__.Father1'>, <class '__main__.Father2'>, <class '__main__.Father3'>)

 

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

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

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

               3.子类中没有,从父类的名称空间中查找

ps:程序的执行顺序是由上到下,父类必须定义在子类之上

对象添加属性的操作, 并不是修改子类的属性

class Goo:
    x=10
    pass
class Foo(Goo):
    x=100
    pass
foo_obj=Foo()

print('对象的名称空间',foo_obj.__dict__)
print('子类的名称空间',Foo.__dict__)
print('父类的名称空间',Goo.__dict__)
foo_obj.x
=10000 print(foo_obj.x) #先从对象自己的名称空间中找。 print('对象的名称空间',foo_obj.__dict__) print('子类的名称空间',Foo.__dict__) print('父类的名称空间',Goo.__dict__) 结果: 10000 对象的名称空间 {'x': 10000} 子类的名称空间 {'__module__': '__main__', 'x': 100, '__doc__': None} 父类的名称空间 {'__module__': '__main__', 'x': 10, '__dict__': <attribute '__dict__' of 'Goo' objects>, '__weakref__': <attribute '__weakref__' of 'Goo' objects>, '__doc__': None}

 

三、派生:

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

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

   派生后继承关系查找验证:

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.f2()                         #调用属性 f2(),因为 子类对象和子类中都没有,所以去父类找,就执行函数 f2(),
                                     #在调用函数f2()时候,把子类对象本身bar_obj当成参数传入给了self
结果:
from Foo.f2...
from Bar.f1..

 

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

        子类继承父类,派生出自己的属性与方法,并且重用父类的属性与方法。是指:子类重新定义一份与父类相同的方法,重用父类的功能,并且派生出自己的属性或方法。

 

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

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

例子:方法1

class OldboyPeople:
    school = 'oldboy'

    def __init__(self, name, age, sex):  # self == tea1, name == 'tank', age == 17, sex == 'male'
        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)     #用_ _init_ _来调用父类的属性 重用了父类的属性或方法
        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)

例子:方法2class OldboyPeople:

    school = 'oldboy'

    # self == tea1
    def __init__(self, name, age, sex):  # self == tea1, name == 'tank', age == 17, sex == 'male'
        self.name = name
        self.age = age
        self.sex = sex
class OldboyTeacher(OldboyPeople):

    def __init__(self, name, age, sex, sal):
        super().__init__(name, age, sex)            # super()是一个特殊的类,调用super得到一个对象,该对象指向父类的名称空间。
        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)         # super()是一个特殊的类,调用super得到一个对象,该对象指向父类的名称空间

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的类,都是经典类。

class User(object):
    pass

class Sub(User):
    pass
print(User.__dict__)    #查看  User类的名称空间  
print(object)

结果:
{'__module__': '__main__', '__dict__': <attribute '__dict__' of 'User' objects>, '__weakref__': <attribute '__weakref__' of 'User' objects>, '__doc__': None}
<class 'object'>




class User:
    pass

class Sub(User):
    pass
print(User.__dict__)    #查看  User类的名称空间  
print(object)

结果:
{'__module__': '__main__', '__dict__': <attribute '__dict__' of 'User' objects>, '__weakref__': <attribute '__weakref__' of 'User' objects>, '__doc__': None}
<class 'object'>

 

 六、super()会严格按照mro列表的顺序往后查找   

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

  mro列表格式: 类名.mro()

class Father1:
    # x = 10
    pass

class Father2:
    # x = 20
    pass

# 多继承的情况下: 从左到右
class Sub(Father1, Father2):

    pass
print(Sub.mro())     #调用mro返回的是一个继承序列

结果:
[<class '__main__.Sub'>, <class '__main__.Father1'>, <class '__main__.Father2'>, <class 'object'>]

 

   例子:

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

结果:
[<class '__main__.C'>, <class '__main__.A'>, <class '__main__.B'>, <class 'object'>]

 

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

mro的查找顺序:
- 新式类:- 广度优先

- 经典类:- 深度优先

新式类:
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') 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() 结果: [<class '__main__.F'>, <class '__main__.D'>, <class '__main__.B'>, <class '__main__.E'>, <class '__main__.C'>, <class '__main__.A'>, <class 'object'>] from F

 

 

            

posted @ 2019-11-26 15:14  薛定谔的猫66  阅读(210)  评论(0)    收藏  举报